目录
显示
题目链接
https://www.luogu.org/problem/P2783
题解
首先按题意用 Tarjan 缩环为点,然后图就变成了一棵树。
接下来就是套路性的树上倍增了。
注意对于 u,v 两个点,u,v 两点的 LCA 会被重复减去两次,统计的时候要把这个点加回去。
#include <cstdio> #include <stack> using namespace std; struct edge { int v,next; }e[100005],e2[100005]; int dfn[10005],low[10005],col[10005],vis[10005],cnte,cntc,cntp,n,m; int head[10005],head2[10005],dep[10005],f[10005][25]; stack<int> s; void addedge(int u,int v) { e[++cnte].v=v; e[cnte].next=head[u]; head[u]=cnte; } void addedge2(int u,int v) { e2[++cnte].v=v; e2[cnte].next=head2[u]; head2[u]=cnte; } void dfs(int u,int fa) { dfn[u]=low[u]=++cntp; vis[u]=1; s.push(u); for(int i=head[u];i;i=e[i].next) { int v=e[i].v; if(v==fa)continue; if(!dfn[v]) { dfs(v,u); low[u]=min(low[u],low[v]); } else if(vis[v])low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { cntc++; while(1) { int p=s.top(); s.pop(); vis[p]=0; col[p]=cntc; if(p==u)break; } } } void dfs2(int u,int fa) { for(int i=head2[u];i;i=e2[i].next) { int v=e2[i].v; if(v!=fa) { dep[v]=dep[u]+1; f[v][0]=u; dfs2(v,u); } } } int lca(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=20;i>=0;i--) if(dep[f[x][i]]>=dep[y])x=f[x][i]; if(x==y)return x; for(int i=20;i>=0;i--) if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } int res[105]; void print(int x) { int cnt=0; while(x) { res[++cnt]=x&1; x>>=1; } for(int i=cnt;i;i--) printf("%d",res[i]); puts(""); } int main() { int q; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } for(int i=1;i<=n;i++) if(!dfn[i])dfs(i,0); cnte=0; for(int i=1;i<=n;i++) for(int j=head[i];j;j=e[j].next) if(col[e[j].v]!=col[i]) addedge2(col[i],col[e[j].v]); f[1][0]=1; dfs2(1,0); for(int i=1;i<=20;i++) for(int j=1;j<=cntc;j++) f[j][i]=f[f[j][i-1]][i-1]; scanf("%d",&q); while(q--) { int u,v; scanf("%d%d",&u,&v); print(dep[col[u]]+dep[col[v]]-2*dep[lca(col[u],col[v])]+1); } return 0; }