Codeforces 231E - Cactus
给一个10^5个点的无向图,每个点最多属于一个环,规定两点之间的简单路:从起点到终点,经过的边不重复
给10^5个询问,每个询问两个点,问这两个点之间有多少条简单路。
挺综合的一道题目,无向图连通分量,缩点,LCA 都考察到了。。
因为每个点最多属于一个环,因此把所有环缩点,就可以得到一棵树
然后对于每个询问,用LCA查找从起点到终点有多少个环
并查集处理的时候挂了一发,注意LCA时合并两个并查集,根节点深度小的作为父亲。。
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<stack> #include<vector> #include<queue> #include<string> #include<sstream> #define eps 1e-9 #define ALL(x) x.begin(),x.end() #define INS(x) inserter(x,x.begin()) #define rep(i,j,k) for(int i=j;i<=k;i++) #define MAXN 100005 #define MAXM 400005 #define INF 0x3fffffff #define PB push_back #define MP make_pair #define X first #define Y second #define clr(x,y) memset(x,y,sizeof(x)); using namespace std; typedef long long LL; int i,j,k,n,m,x,y,T,big,cas,len; bool flag; int edge,head[MAXN],bin[MAXN],headS[MAXN],edgeS,vis[MAXN],d[MAXN],id[MAXN],num[MAXN]; struct edgenode { int to,next,flag; } G[MAXM],S[MAXM]; void add_edge(int x,int y) { G[edge].to=y; G[edge].flag=0; G[edge].next=head[x]; head[x]=edge++; } void add_edgeS(int x,int y) { S[edgeS].to=y; S[edgeS].flag=0; S[edgeS].next=headS[x]; headS[x]=edgeS++; } int fa[MAXN]; int findset(int x) { return x==fa[x]?x:fa[x]=findset(fa[x]); } void unionset(int x,int y) { fa[findset(x)]=findset(y); } int dfn[MAXN],low[MAXN],time; void dfs(int u,int fa) { vis[u]=1; dfn[u]=low[u]=++time; for (int i=head[u];i!=-1;i=G[i].next) { int v=G[i].to; if (v!=fa && vis[v]==1) { low[u]=min(low[u],dfn[v]); } if (!vis[v]) { dfs(v,u); low[u]=min(low[u],low[v]); if (low[v]>dfn[u]) G[i].flag=1; } } vis[u]=2; } void dive(int u,int scc) { id[u]=scc; vis[u]=1; num[scc]++; for (int i=head[u];i!=-1;i=G[i].next) { if (!G[i].flag && !vis[G[i].to]) dive(G[i].to,scc); } } void dis(int u,int dep)//记录当前节点到根节点有多少个“环” { vis[u]=1; d[u]=dep; for (int i=headS[u];i!=-1;i=S[i].next) { int v=S[i].to; if (!vis[v]) { if (num[v]>2) dis(v,dep+1); else dis(v,dep); } } } vector<pair<int,int> > Q[MAXN]; int ans[MAXN]; void tarjan(int u) { vis[u]=true; for (int i=0;i<Q[u].size();i++) { int v=Q[u][i].X,id=Q[u][i].Y; if (vis[v]) { int com=findset(v); ans[id]=d[u]+d[v]-2*d[com]; if (num[com]>2) ans[id]++; } } for (int i=headS[u];i!=-1;i=S[i].next) { int v=S[i].to; if (!vis[v]) { tarjan(v); unionset(v,u); } } } int main() { memset(head,-1,sizeof(head)); edge=0; memset(headS,-1,sizeof(headS)); edgeS=0; scanf("%d%d",&n,&m); while (m--) { scanf("%d%d",&x,&y); add_edge(x,y); add_edge(y,x); } dfs(1,-1); memset(vis,0,sizeof(vis)); int scc=1; for (int i=1;i<=n;i++) { if (!vis[i]) dive(i,scc++); } for (i=1;i<=n;i++) { for (int j=head[i];j!=-1;j=G[j].next) { int v=G[j].to; if (id[i]!=id[v]) { add_edgeS(id[i],id[v]); add_edgeS(id[v],id[i]); } } } int q; scanf("%d",&q); for (i=0;i<q;i++) { scanf("%d%d",&x,&y); x=id[x];y=id[y]; Q[x].PB(MP(y,i)); Q[y].PB(MP(x,i)); } memset(vis,0,sizeof(vis)); if (num[1]>2) dis(1,1); else dis(1,0); memset(vis,0,sizeof(vis)); for (i=1;i<=n;i++) fa[i]=i; tarjan(1); bin[0]=1; for(int i=1;i<MAXN;i++) bin[i]=bin[i-1]*2%1000000007; for (int i=0;i<q;i++) { printf("%d\n",bin[ans[i]]); } return 0; }