3667. 【HNOI2014】世界树(worldtree)
3667. 【HNOI2014】世界树(worldtree)
首先我们对于每次询问建立一个虚树
然后对于虚树上每一个点我们先做一遍dfs预处理出离它最近的可行点和距离;
然后对一个可行点x我们就先ans[x]+=size[x];接着遍历x的儿子假设是y,如果y也是可行点那么就寻找x和y之间的分界点分别给y加上答案,再给x减去属于y的答案。如果y是中间点(建虚树时的LCA但不是可行点)那么就寻找x与离y最近的点的分界点进行同样的操作,记得答案要加给离y最近的点。
如果x是中间点,那么我们就用离x最近的点假设是x'进行上面的操作(具体的自己可以思考一下,细节还挺多的。)
然后就完结了
我的代码又丑又长:阅读需谨慎
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=600001; struct nup{int id,qz;}a[N]; int n,x,y,m,i,j,k,l,e[N][3],h[N],size[N],dfn[N],in[N],out[N],tot,num,cnt,fz[N][20],z[N],h1[N],e1[N][3],tot1,ans[N],dep[N],bz1[N],b[N],fa[N],V[N][2]; bool cmp(nup x,nup y){return x.qz<y.qz;} void dfs(int x,int father) { size[x]++;in[x]=++num;dfn[num]=x;fz[x][0]=father;dep[x]=dep[father]+1; for(int i=h[x];i;i=e[i][0]) if(e[i][1]!=father) dfs(e[i][1],x),size[x]+=size[e[i][1]]; out[x]=num; } void add(int u,int v) { e[++tot][0]=h[u]; e[tot][1]=v; h[u]=tot; } void add1(int u,int v) { e1[++tot1][0]=h1[u]; e1[tot1][1]=v; h1[u]=tot1; } int LCA(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int i=19;i>=0;i--) if(dep[fz[x][i]]>=dep[y]) x=fz[x][i]; if(x==y) return x; for(int i=19;i>=0;i--) if(fz[x][i]!=fz[y][i]) x=fz[x][i],y=fz[y][i]; x=fz[x][0];return x; } void build_xs(int num) { sort(a+1,a+1+num,cmp); int top=1;z[top]=1;h1[1]=0;tot1=0; for(int i=1;i<=num;i++) if(a[i].id!=1) { int lca=LCA(a[i].id,z[top]); if(lca!=z[top]) { while(in[z[top-1]]>in[lca]) add1(z[top-1],z[top]),top--; if(in[lca]!=in[z[top-1]]) h1[lca]=0,add1(lca,z[top]),z[top]=lca; else add1(lca,z[top]),top--; } h1[a[i].id]=0;z[++top]=a[i].id; } for(int i=top;i>1;i--) add1(z[i-1],z[i]); } int find(int x,int wz,int y,int wz1,int bh,int bh1) { int mid=0; wz=wz-wz1; if((dep[y]-wz-dep[x])%2==1) mid=(dep[y]-wz-dep[x])/2+dep[x]; else { if(bh<bh1) mid=dep[x]+(dep[y]-wz-dep[x])/2; else mid=dep[x]+(dep[y]-wz-dep[x])/2-1; } mid++;if(mid<dep[x]) mid=dep[x]+1; for(int i=19;i>=0;i--) if(dep[fz[y][i]]>=mid) y=fz[y][i]; return y; } void dfs2(int x,int father) { int num=1e9+7,wz=0; for(int i=h1[x];i;i=e1[i][0]) if(e1[i][1]!=father) { dfs2(e1[i][1],x); if(bz1[e1[i][1]]==1) { if((dep[e1[i][1]]-dep[x])<num) num=(dep[e1[i][1]]-dep[x]),wz=e1[i][1]; else if((dep[e1[i][1]]-dep[x])==num&&wz>e1[i][1]) num=(dep[e1[i][1]]-dep[x]),wz=e1[i][1]; } else { if((V[e1[i][1]][0]+dep[e1[i][1]]-dep[x])<num) num=(V[e1[i][1]][0]+dep[e1[i][1]]-dep[x]),wz=V[e1[i][1]][1]; else if((V[e1[i][1]][0]+dep[e1[i][1]]-dep[x])==num&&wz>V[e1[i][1]][1]) num=(V[e1[i][1]][0]+dep[e1[i][1]]-dep[x]),wz=V[e1[i][1]][1]; } } V[x][0]=num;V[x][1]=wz; } void dfs1(int x,int father) { if(x==493) l=0; fa[x]=father; int num=1e9+7,wz=0; for(int i=h1[x];i;i=e1[i][0]) if(e1[i][1]!=father) dfs1(e1[i][1],x); if(bz1[x]==1) { ans[x]+=size[x]; for(int i=h1[x];i;i=e1[i][0]) if(e1[i][1]!=father) { if(bz1[e1[i][1]]==1) { int cnt=find(x,0,e1[i][1],0,x,e1[i][1]); ans[x]-=size[cnt]; ans[e1[i][1]]+=size[cnt]-size[e1[i][1]]; } else { if((dep[e1[i][1]]-dep[x])>V[e1[i][1]][0]||((dep[e1[i][1]]-dep[x])==V[e1[i][1]][0]&&V[e1[i][1]][1]<x)) { int cnt=find(x,0,e1[i][1],V[e1[i][1]][0],x,V[e1[i][1]][1]); ans[x]-=size[cnt]; ans[V[e1[i][1]][1]]+=size[cnt]-size[e1[i][1]]; } else { ans[x]-=size[e1[i][1]]; } } } } else { num=V[x][0],wz=V[x][1]; int ll=x,llr=0; while(bz1[ll]==0&&fa[ll]!=0) { llr+=dep[ll]-dep[fa[ll]]; ll=fa[ll]; if(bz1[ll]==0) {if((V[ll][0]+llr)<num||((V[ll][0]+llr)==num&&V[ll][1]<wz)) wz=V[ll][1],num=(V[ll][0]+llr);} else if(llr<num||(llr==num&&wz>ll)) num=llr,wz=ll; } ans[wz]+=size[x]; for(int i=h1[x];i;i=e1[i][0]) if(e1[i][1]!=father&&e1[i][1]!=wz&&V[e1[i][1]][1]!=wz) { if(bz1[e1[i][1]]==0) { int cnt=find(x,num,e1[i][1],V[e1[i][1]][0],wz,V[e1[i][1]][1]); ans[wz]-=size[cnt]; ans[V[e1[i][1]][1]]+=size[cnt]-size[e1[i][1]]; } else { int cnt=find(x,num,e1[i][1],0,wz,e1[i][1]); ans[wz]-=size[cnt]; ans[e1[i][1]]+=size[cnt]-size[e1[i][1]]; } } else if((e1[i][1]==wz||(V[e1[i][1]][1]==wz))&&wz!=father) ans[wz]-=size[e1[i][1]]; } } int main() { freopen("worldtree.in","r",stdin); freopen("worldtree.out","w",stdout); scanf("%d",&n); for(i=1;i<n;i++) {scanf("%d%d",&x,&y);add(x,y);add(y,x);} dfs(1,0); for(i=1;i<=19;i++) for(j=1;j<=n;j++) fz[j][i]=fz[fz[j][i-1]][i-1]; scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d",&k);memset(ans,0,sizeof ans); for(j=1;j<=k;j++) scanf("%d",&a[j].id),a[j].qz=in[a[j].id],bz1[a[j].id]=1,b[j]=a[j].id;//remember to clear the array bz1; build_xs(k); dfs2(1,0); dfs1(1,0); for(j=1;j<=k;j++) printf("%d ",ans[b[j]]),ans[b[j]]=0,bz1[b[j]]=0; printf("\n"); } }