Rada and the Chamomile Valley(Tarjan缩点+多源BFS)
https://codeforces.com/contest/2132/problem/F
思路:如果某条边是1到n必然经过的边(即任意一条1到n的路径都包含这条边),那么删掉这条边后,1和n必然不在同一个连通块中。
对于一个无向图,如果删掉一条边后图中的连通分量数增加了,则称这条边为桥或者割边。严谨来说,就是:假设有连通图 G={V,E}, e 是其中一条边(即 e∈E),如果 G−e 是不连通的,则边 e 是图 G 的一条割边(桥)。
因此1到n必然经过的边就是桥了,我们通过Tarjan算法缩点,那么原图就会变成一棵无向树。树中连接着每个节点(连通分量)就是原图中的桥了。接着还需要找到从1到n一定会经过的桥,这时只需要以1所在的连通分量为起点,对缩点后的树进行dfs,找到到达n所在连通分量的所有边(桥),将这些边构成的集合记为E,E中每条边的两个端点构成的集合记为V。
对于每次询问的节点u,如果每次都跑一遍bfs显然超时,考虑到每个查询都关注节点到V中节点的最短距离,我们可以转换思路:以V中节点作为源点进行多源bfs,这样得到的结果等价于原图中任意节点到V中节点的最短距离。在bfs过程中再额外维护距离节点最近的边的编号(E中的边),这样就可以通过一次bfs求得任意一个点的答案,查询时间O(1)。
大致步骤如下:
1.建原图,将编号看作边权
2.对原图跑Tarjan算法,确定每个节点所在连通分量的编号,每个连通分量的编号对应缩点后无向树的节点编号
3.接着建立无向树,遍历原图所有边,如果该边的两个端点不在同一个连通分量,则说明该边是桥,同时对这两个连通分量进行连边
4.然后以1所在的连通分量对应的节点为根,对无向树进行dfs,并在这个过程中维护一个数组用来记录访问到当前节点所经过的边的编号(对应边权)。当访问到n时,此时数组就记录了从1到n必然经过的边。
5.枚举所有被记录的边,将两端的端点压入到bfs队列中,为避免重复操作,要对已压入的点进行标记。在维护最短距离的同时,再维护到达V中节点编号最小的边。
Code:
//#define int long long
int h1[N],h2[N],w[N*4],ne[N*4],e[N*4],idx;
int cnt,tot,top,dfn[N],stk[N],low[N],scc[N];
int vis[N],n,m;void add(int *h,int a,int b,int c)
{e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}void Tarjan(int u,int fa)
{low[u]=dfn[u]=++tot;stk[++top]=u;for(int i=h1[u];~i;i=ne[i]){int j=e[i];if(!dfn[j]){Tarjan(j,i);low[u]=min(low[u],low[j]);}else if(i!=(fa^1)) low[u]=min(low[u],dfn[j]);}if(low[u]==dfn[u]){cnt++;int y;do{y=stk[top--];scc[y]=cnt;}while(y!=u);}
}bool dfs(int u,int fa)
{if(u==scc[n]) return true;for(int i=h2[u];~i;i=ne[i]){int j=e[i];if(j==fa) continue;vis[w[i]]=true;if(dfs(j,u)) return true;vis[w[i]]=false;}return false;
}
void solve()
{cin>>n>>m;memset(h1, -1, n + 1 << 2);//int占4个字节,memset的第三位代表字节大小//如果用longlong,就要乘8memset(dfn, 0,n + 1 << 2);// memset(low,0,sizeof low);// memset(vis,0,sizeof vis);idx=0;for(int i=1;i<=m;i++){int a,b;cin>>a>>b;add(h1,a,b,i);add(h1,b,a,i);}tot=cnt=0;Tarjan(1,-1);memset(h2,-1, cnt + 1 << 2);for(int i=1;i<=n;i++){for(int j=h1[i];~j;j=ne[j]){int u=scc[i],v=scc[e[j]],c=w[j];if(u!=v) add(h2,u,v,c);}}dfs(scc[1],0);queue<int> q;vector<bool> st(n+1,false);vector<int> bh(n+1,1e9),dist(n+1,1e9);for(int i=1;i<=n;i++){for(int j=h1[i];~j;j=ne[j]){int u=i,v=e[j],c=w[j];if(vis[c]){bh[u]=min(bh[u],c);bh[v]=min(bh[v],c);if(!st[u]){q.push(u);dist[u]=0;st[u]=true;}if(!st[v]){q.push(v);dist[v]=0;st[v]=true;}vis[c]=false;}}}while(q.size()){auto t=q.front();q.pop();for(int i=h1[t];~i;i=ne[i]){int j=e[i];if(dist[j]>dist[t]+1){dist[j]=dist[t]+1;bh[j]=bh[t];q.push(j);}else if(dist[j]==dist[t]+1)bh[j]=min(bh[j],bh[t]);}}cin>>m;while(m--){int k;cin>>k;cout<<(bh[k]==1e9?-1:bh[k])<<' ';}cout<<endl;
}
signed main()
{ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);int t;cin>>t;//t=1;while(t--) solve();
}
参考博客:F. Rada and the Chamomile Valley - onlyblues - 博客园