bzoj3572: [Hnoi2014]世界树
首先先套路上虚树
对于虚树,分成两类点:一种是作为议事处的,一种是虚树加的lca
如果树上没有加的点,对于两个议事处之间的路径,一半归下面,一半归上面,这个就很好解决了
对于lca,我们需要找到在树上离它最近的议事处,此时lca相当于帮这个议事处去和其他的点分配路径上的点
这个我们用二次扫描+换根法就可以弄出来
说得轻巧码量巨大
叫我AK·再做数据结构我是狗·C·真香·qhzdy
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[610000];int len,last[310000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int z,ys[310000]; int Bin[30],f[30][310000],dep[310000],tot[310000]; void dfs(int x) { ys[x]=++z; tot[x]=1; for(int i=1;Bin[i]<=dep[x];i++)f[i][x]=f[i-1][f[i-1][x]]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=f[0][x]) { f[0][y]=x; dep[y]=dep[x]+1; dfs(y); tot[x]+=tot[y]; } } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=25;i>=0;i--) if(dep[x]-dep[y]>=Bin[i])x=f[i][x]; if(x==y)return x; for(int i=25;i>=0;i--) if(dep[x]>=Bin[i]&&f[i][x]!=f[i][y])x=f[i][x],y=f[i][y]; return f[0][x]; } int findkth(int x,int k) { for(int i=25;i>=0;i--) if(k>=Bin[i])x=f[i][x],k-=Bin[i]; return x; } //---------------------------------------init----------------------------------------------------------- int c[310000]; int h[310000],h2[310000]; bool cmp(int h1,int h2){return ys[h1]<ys[h2];} node e[610000];int elen,elast[310000]; void eins(int x,int y) { elen++; e[elen].x=x;e[elen].y=y; e[elen].next=elast[x];elast[x]=elen; } ///~~~~~~~~~~~~边目录~~~~~~~~~~~~~~~~~~ int top,sta[310000];bool islca[310000]; void VirtualTree(int m) { sort(h+1,h+m+1,cmp); top=0;sta[++top]=1; for(int i=1;i<=m;i++) { int lca=LCA(h[i],sta[top]); while(1) { if(dep[lca]>=dep[sta[top-1]]&&lca!=sta[top-1]&&lca!=sta[top]) { eins(lca,sta[top]);top--; sta[++top]=lca; break; } if(lca==sta[top])break; bool bk=(lca==sta[top-1]); if(top>1) eins(sta[top-1],sta[top]),top--; if(bk)break; } if(h[i]!=sta[top])sta[++top]=h[i]; islca[h[i]]=false; } while(top>1) eins(sta[top-1],sta[top]),top--; } //--------------------------------------composition----------------------------------------------------------- int p[2][310000],dis[2][310000],hp[310000],hd[310000]; int d1,d2; bool check(int x,int y,int w) { if(y==-1)return false; if(p[w][x]==-1)return true; return d1==d2?p[w][x]>y:d1>d2; } //~~~~~~~~~~~烦人的check~~~~~~~~~~~~~ void solvert(int x,int fr) { p[0][x]=p[1][x]=-1; if(!islca[x])p[0][x]=x,dis[0][x]=0; for(int k=elast[x];k;k=e[k].next) { int y=e[k].y; if(y!=fr) { solvert(y,x); bool bk=false; d1=dis[0][x],d2=dis[0][y]+dep[y]-dep[x]; if(check(x,p[0][y],0)) { bk=true; p[0][x]=p[0][y], dis[0][x]=d2; d1=dis[1][x],d2=dis[1][y]+dep[y]-dep[x]; if(check(x,p[1][y],1)) p[1][x]=p[1][y], dis[1][x]=d2; } d1=dis[1][x],d2=dis[0][y]+dep[y]-dep[x]; if(!bk&&check(x,p[0][y],1)) p[1][x]=p[0][y], dis[1][x]=d2; } } } void changert(int x,int fr) { hp[x]=p[0][x],hd[x]=dis[0][x]; for(int k=elast[x];k;k=e[k].next) { int y=e[k].y; if(y!=fr) { if(p[0][x]==p[0][y]) { d1=dis[0][y],d2=dis[1][x]+dep[y]-dep[x]; if(check(y,p[1][x],0)) p[0][y]=p[1][x], dis[0][y]=d2; } else { d1=dis[0][y],d2=dis[0][x]+dep[y]-dep[x]; if(check(y,p[0][x],0)) p[0][y]=p[0][x], dis[0][y]=d2; } changert(y,x); } } } //--------------------------------------换根inithp----------------------------------------------------------- void calc(int x,int y) { if(hp[x]==hp[y]) { int yy=findkth(y,dep[y]-dep[x]-1); c[hp[x]]+=tot[yy]-tot[y]; } else { int pt=dep[y]-dep[x]-1+hd[x]+hd[y]; int xx=findkth(y,dep[y]-dep[x]-1); int yy=findkth(y,pt/2+((pt%2==1)?(hp[y]<hp[x]):0)-hd[y]); c[hp[x]]+=tot[xx]-tot[yy]; c[hp[y]]+=tot[yy]-tot[y]; } } void solve(int x,int fr) { c[hp[x]]+=tot[x]; for(int k=elast[x];k;k=e[k].next) { int y=e[k].y; if(y!=fr) { c[hp[x]]-=tot[findkth(y,dep[y]-dep[x]-1)]; calc(x,y); solve(y,x); } } elast[x]=0; islca[x]=true; hp[x]=hd[x]=-1; } //---------------------------------------------solve--------------------------------------------------------- int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n,x,y; scanf("%d",&n); len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); ins(x,y),ins(y,x); } Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2; dep[1]=0;dfs(1); int Q,m; scanf("%d",&Q); memset(hp,-1,sizeof(hp)); memset(islca,true,sizeof(islca)); while(Q--) { scanf("%d",&m); for(int i=1;i<=m;i++) scanf("%d",&h[i]),h2[i]=h[i]; VirtualTree(m); solvert(1,0); changert(1,0); solve(1,0);elen=0; for(int i=1;i<m;i++)printf("%d ",c[h2[i]]),c[h2[i]]=0; printf("%d\n",c[h2[m]]),c[h2[m]]=0; } return 0; }
pain and happy in the cruel world.