标签:cst std 输出 using ring void 双向 size lca
$n$个城市,从$1$到$n$标号,$n$个城市构成一棵树。
有$m$条双向公交路线,对于每条路线,公交沿着两个终点站之间的最短路径行驶并会在沿途各站停车。从一个城市只能坐公交前往其他城市。
有$q$个询问:从一个城市到另一个城市要搭乘多少趟公交?不能到达输出$-1$。
对于每个询问$x,y$,求出$z=lca(x,y)$。
先从$x$和$y$出发到达$z$下方的城市$x‘$和$y‘$使得再坐一趟车可到$z$,记步数和为$s$。倍增,预处理$f[i][j]$表示从$i$出发坐$2^{j}$趟车最上能到达的位置。
若$x‘$可坐车到$y‘$则答案为$s+1$,否则答案为$s+2$。
考虑dfs过程中用树状数组按dfs序维护,若$x‘$的子树中终点站在$y‘$子树内的车,那么可以坐一趟车到达。预处理时把公交和询问分别挂在对应端点上。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 const int N=200010,K=19; 7 struct ask { 8 int y,id,s; 9 ask () {} 10 ask (int y,int id,int s):y(y),id(id),s(s) {} 11 }; 12 int n,m,q,x,y,z,f[N][K],ans[N],c[N],sum[N]; 13 int cnt,dfn[N],fa[N],son[N],top[N],dep[N],size[N]; 14 int p,head[N],to[N],nxt[N]; 15 vector<int> h[N]; 16 vector<ask> A[N]; 17 inline int read() { 18 int re=0; char ch=getchar(); 19 while (ch<‘0‘||ch>‘9‘) ch=getchar(); 20 while (ch>=‘0‘&&ch<=‘9‘) re=re*10+ch-48,ch=getchar(); 21 return re; 22 } 23 inline void add(int x,int y) { 24 to[++p]=y; nxt[p]=head[x]; head[x]=p; 25 } 26 void tree_add(int x) {for (; x<=n; x+=(x&-x)) ++c[x];} 27 int tree_sum(int x) {int re=0; for (; x; x-=(x&-x)) re+=c[x]; return re;} 28 void dfs1(int x) { 29 size[x]=1; dfn[x]=++cnt; 30 for (int i=head[x]; i; i=nxt[i]) { 31 dep[to[i]]=dep[x]+1; 32 dfs1(to[i]); 33 size[x]+=size[to[i]]; 34 if (size[to[i]]>size[son[x]]) son[x]=to[i]; 35 } 36 } 37 void dfs2(int x,int tp) { 38 top[x]=tp; 39 if (son[x]) dfs2(son[x],tp); 40 for (int i=head[x]; i; i=nxt[i]) { 41 if (to[i]==son[x]) continue; 42 dfs2(to[i],to[i]); 43 } 44 } 45 void dfs3(int x) { 46 for (int i=head[x]; i; i=nxt[i]) { 47 dfs3(to[i]); 48 if (dep[f[to[i]][0]]<dep[f[x][0]]) f[x][0]=f[to[i]][0]; 49 } 50 } 51 void dfs4(int x) { 52 for (int i=0; i<A[x].size(); i++) { 53 A[x][i].s=tree_sum(dfn[A[x][i].y]+size[A[x][i].y]-1)-tree_sum(dfn[A[x][i].y]-1); 54 } 55 for (int i=0; i<h[x].size(); i++) tree_add(dfn[h[x][i]]); 56 int tmp; 57 for (int i=head[x]; i; i=nxt[i]) dfs4(to[i]); 58 for (int i=0; i<A[x].size(); i++) { 59 tmp=tree_sum(dfn[A[x][i].y]+size[A[x][i].y]-1)-tree_sum(dfn[A[x][i].y]-1); 60 if (tmp==A[x][i].s) ans[A[x][i].id]++; 61 } 62 } 63 int lca(int a,int b) { 64 while (top[a]!=top[b]) { 65 if (dep[top[a]]>dep[top[b]]) swap(a,b); 66 b=fa[top[b]]; 67 } 68 if (dep[a]>dep[b]) swap(a,b); 69 return a; 70 } 71 int main() { 72 n=read(); 73 for (int i=2; i<=n; i++) add(fa[i]=read(),i); 74 dfs1(1); dfs2(1,1); 75 m=read(); 76 for (int i=1; i<=n; i++) f[i][0]=i; 77 for (int i=1; i<=m; i++) { 78 x=read(); y=read(); 79 h[x].push_back(y); h[y].push_back(x); 80 z=lca(x,y); 81 if (dep[z]<dep[f[x][0]]) f[x][0]=z; 82 if (dep[z]<dep[f[y][0]]) f[y][0]=z; 83 } 84 dfs3(1); 85 for (int j=1; j<K; j++) 86 for (int i=1; i<=n; i++) 87 f[i][j]=f[f[i][j-1]][j-1]; 88 q=read(); 89 for (int i=1; i<=q; i++) { 90 x=read(); y=read(); z=lca(x,y); 91 if (x==y) continue; 92 if (f[x][K-1]!=f[y][K-1]) {ans[i]=-1; continue;} 93 for (int j=K-1; j>=0; j--) { 94 if (dep[f[x][j]]>dep[z]) ans[i]+=(1<<j),x=f[x][j]; 95 if (dep[f[y][j]]>dep[z]) ans[i]+=(1<<j),y=f[y][j]; 96 } 97 ans[i]++; 98 if (z!=x && z!=y) A[x].push_back(ask(y,i,0)); 99 } 100 dfs4(1); 101 for (int i=1; i<=q; i++) printf("%d\n",ans[i]); 102 return 0; 103 }
CF983E NN country [倍增][LCA][树状数组]
标签:cst std 输出 using ring void 双向 size lca
原文地址:https://www.cnblogs.com/hnooo/p/10016132.html