[lca][并差集][bfs] Jzoj P3717 火车
题解
- 其实就是按顺序的求lca,求两点之见的经过的道路数量
- 对于要走到的那个点,如果之前到过的,就不用走了
- 没到过的话,lca计算距离,暴力标记路径中的点,并查集维护点不被重复标记
- 对,还有一个,直接dfs建树会炸栈,就bfs罗
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 struct edge {int to,from;}e[500010*2]; 6 int head[500010],cnt,n,m,a,dep[500010],state[500010],fa[500010]; 7 long long f[500010][21],ans,mi[21]; 8 void insert(int x,int y) { e[++cnt].to=y; e[cnt].from=head[x]; head[x]=cnt; } 9 int getfather(int x) { return fa[x]==x?x:fa[x]=getfather(fa[x]); } 10 void bfs() 11 { 12 int l=0,r=1; 13 state[1]=1,dep[1]=1; 14 while (l<r) 15 { 16 l++; 17 for (int i=head[state[l]];i;i=e[i].from) 18 if (!dep[e[i].to]) 19 { 20 r++; 21 dep[e[i].to]=dep[state[l]]+1; 22 state[r]=e[i].to; 23 f[e[i].to][0]=state[l]; 24 } 25 } 26 } 27 int getlca(int x,int y,long long &ans) 28 { 29 if (dep[x]<dep[y]) swap(x,y); 30 for (int i=20;i>=0;i--) 31 if (dep[f[x][i]]>=dep[y]) 32 ans+=mi[i],x=f[x][i]; 33 if (x==y) return x; 34 for (int i=20;i>=0;i--) 35 if (f[x][i]!=f[y][i]) 36 ans+=mi[i+1],x=f[x][i],y=f[y][i]; 37 ans+=2; 38 return f[x][0]; 39 } 40 int main() 41 { 42 freopen("train.in","r",stdin); 43 freopen("train.out","w",stdout); 44 scanf("%d%d%d",&n,&m,&a); 45 for (int i=1;i<=n-1;i++) 46 { 47 int u,v; 48 scanf("%d%d",&u,&v); 49 insert(u,v),insert(v,u); 50 } 51 bfs(); 52 for (int i=1;i<=n;i++) fa[i]=i; 53 mi[0]=1; for (int i=1;i<=20;i++) mi[i]=mi[i-1]*2; 54 for (int i=1;i<=20;i++) 55 for (int j=1;j<=n;j++) 56 f[j][i]=f[f[j][i-1]][i-1]; 57 for (int i=1;i<=m;i++) 58 { 59 int x; 60 scanf("%d",&x); 61 if (getfather(x)!=x) continue; 62 int lca=getlca(a,x,ans); 63 int u=getfather(a),v=getfather(x); 64 while (u!=v) 65 { 66 if (dep[u]<dep[v]) swap(u,v); 67 u=fa[u]=getfather(f[u][0]); 68 } 69 if (getfather(lca)==lca) fa[lca]=f[lca][0]; 70 a=x; 71 } 72 printf("%lld",ans); 73 return 0; 74 }