「BZOJ3572」[HNOI2014]世界树
建出虚树
两遍dp求出虚树上的各点被哪个点管辖
再对虚树上的每一条边计算贡献
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=300010,P=25,oo=2e9; 4 int n,m,q,a[N]; 5 int fa[N][P],dep[N],id[N],siz[N],dfn; 6 int ans[N],b[N],c[N],f[N],d[N],w[N]; 7 struct Edge{ 8 int from,to,v,next; 9 Edge(int _from=0,int _to=0,int _v=0,int _next=0):from(_from),to(_to),v(_v),next(_next){} 10 }edge[N<<1]; 11 int edge_tot,last[N]; 12 inline void add_edge(int f,int t,int vv){edge[++edge_tot]=Edge(f,t,vv,last[f]),last[f]=edge_tot;return;} 13 int cmp(int x,int y){return id[x]<id[y];} 14 void dfs(int k,int father,int d){ 15 fa[k][0]=father,dep[k]=d,id[k]=++dfn,siz[k]=1; 16 for(int i=last[k];i;i=edge[i].next){ 17 if(edge[i].to==father) continue; 18 dfs(edge[i].to,k,d+1); 19 siz[k]+=siz[edge[i].to]; 20 } 21 return; 22 } 23 int getlca(int x,int y){ 24 if(dep[x]<dep[y]) swap(x,y); 25 for(int i=19;i>=0;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; 26 if(x==y) return x; 27 for(int i=19;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; 28 return fa[x][0]; 29 } 30 inline int getson(int x,int y){ 31 for(int i=19;i>=0;i--) if(dep[fa[y][i]]>dep[x]) y=fa[y][i]; 32 return y; 33 } 34 int sta[N],top; 35 inline void build(){ 36 int lca; 37 if(f[1]!=1) sta[top++]=1; 38 for(int i=1;i<=m;i++){ 39 while(1){ 40 if(!top) break; 41 lca=getlca(sta[top-1],a[i]); 42 if(lca==sta[top-1]) break; 43 else{ 44 top--; 45 if(id[sta[top-1]]>=id[lca]){ 46 add_edge(sta[top-1],sta[top],siz[getson(sta[top-1],sta[top])]-siz[sta[top]]); 47 }else{ 48 add_edge(lca,sta[top],siz[getson(lca,sta[top])]-siz[sta[top]]); 49 sta[top++]=lca; 50 break; 51 } 52 } 53 } 54 sta[top++]=a[i]; 55 } 56 while(top>=2){top--;add_edge(sta[top-1],sta[top],siz[getson(sta[top-1],sta[top])]-siz[sta[top]]);} 57 return; 58 } 59 void dfs_dp1(int k,int father){ 60 c[++dfn]=k,w[k]=siz[k]; 61 for(int i=last[k];i;i=edge[i].next){ 62 if(edge[i].to==father) continue; 63 w[k]-=siz[edge[i].to]+edge[i].v; 64 dfs_dp1(edge[i].to,k); 65 if(d[k]>d[edge[i].to]+dep[edge[i].to]-dep[k]) d[k]=d[edge[i].to]+dep[edge[i].to]-dep[k],f[k]=f[edge[i].to]; 66 else if(d[k]==d[edge[i].to]+dep[edge[i].to]-dep[k]&&f[edge[i].to]<f[k]) f[k]=f[edge[i].to]; 67 } 68 return; 69 } 70 void dfs_dp2(int k,int father){ 71 for(int i=last[k];i;i=edge[i].next){ 72 if(edge[i].to==father) continue; 73 if(d[edge[i].to]>d[k]+dep[edge[i].to]-dep[k]) d[edge[i].to]=d[k]+dep[edge[i].to]-dep[k],f[edge[i].to]=f[k]; 74 else if(d[edge[i].to]==d[k]+dep[edge[i].to]-dep[k]&&f[edge[i].to]>f[k]) f[edge[i].to]=f[k]; 75 dfs_dp2(edge[i].to,k); 76 } 77 return; 78 } 79 inline void solve(int k){ 80 int t1=edge[k].from,t2=edge[k].to,nxt; 81 if(f[t1]==f[t2]){ans[f[t1]]+=edge[k].v;return;} 82 int mid=t2; 83 for(int i=19;i>=0;i--){ 84 nxt=fa[mid][i]; 85 if(id[nxt]<id[t1]) continue; 86 if(d[t1]+dep[nxt]-dep[t1]>d[t2]+dep[t2]-dep[nxt]||(d[t1]+dep[nxt]-dep[t1]==d[t2]+dep[t2]-dep[nxt])&&f[t2]<f[t1]) mid=nxt; 87 } 88 ans[f[t1]]+=siz[getson(t1,mid)]-siz[mid]; 89 ans[f[t2]]+=siz[mid]-siz[t2]; 90 return; 91 } 92 inline void clear(){ 93 for(int i=1;i<=dfn;i++) last[c[i]]=f[c[i]]=ans[c[i]]=w[c[i]]=0,d[c[i]]=oo; 94 edge_tot=dfn=top=0; 95 return; 96 } 97 void query(){ 98 int t1,t2; 99 scanf("%d",&m); 100 for(int i=1;i<=m;i++) scanf("%d",&a[i]),b[i]=a[i],f[a[i]]=a[i],d[a[i]]=0; 101 sort(a+1,a+m+1,cmp); 102 build(); 103 dfs_dp1(1,0);dfs_dp2(1,0); 104 for(int i=1;i<=dfn;i++) ans[f[c[i]]]+=w[c[i]]; 105 for(int i=1;i<=edge_tot;i++) 106 solve(i); 107 for(int i=1;i<=m;i++) printf("%d ",ans[b[i]]); 108 printf("\n"); 109 clear(); 110 return; 111 } 112 int main(){ 113 int t1,t2; 114 scanf("%d",&n); 115 for(int i=1;i<n;i++){ 116 scanf("%d%d",&t1,&t2); 117 add_edge(t1,t2,0);add_edge(t2,t1,0); 118 } 119 dfs(1,0,1); 120 for(int i=1;i<=19;i++) 121 for(int j=1;j<=n;j++) 122 fa[j][i]=fa[fa[j][i-1]][i-1]; 123 memset(last,0,sizeof(last));memset(d,127/2,sizeof(d)); 124 edge_tot=dfn=0; 125 scanf("%d",&q); 126 while(q--) query(); 127 return 0; 128 }