bzoj 3572: [Hnoi2014]世界树

来源:互联网 发布:php集成开发环境 编辑:程序博客网 时间:2024/06/04 19:02

Description

世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相同。有的聚居地之间有双向的道路相连,道路的长度为1。保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环。定义两个聚居地之间的距离为连接他们的道路的长度;例如,若聚居地a和b之间有道路,b和c之间有道路,因为每条道路长度为1而且又不可能出现环,所卧a与c之间的距离为2。
出于对公平的考虑,第i年,世界树的国王需要授权m[i]个种族的聚居地为临时议事处。对于某个种族x(x为种族的编号),如果距离该种族最近的临时议事处为y(y为议事处所在聚居地的编号),则种族x将接受y议事处的管辖(如果有多个临时议事处到该聚居地的距离一样,则y为其中编号最小的临时议事处)。
现在国王想知道,在q年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。

Input

第一行为一个正整数n,表示世界树中种族的个数。
接下来n-l行,每行两个正整数x,y,表示x聚居地与y聚居地之间有一条长度为1的双
向道路。接下来一行为一个正整数q,表示国王询问的年数。
接下来q块,每块两行:
第i块的第一行为1个正整数m[i],表示第i年授权的临时议事处的个数。
第i块的第二行为m[i]个正整数h[l]、h[2]、…、h[m[i]],表示被授权为临时议事处的聚居地编号(保证互不相同)。

Output

输出包含q行,第i行为m[i]个整数,该行的第j(j=1,2…,,m[i])个数表示第i年被授权的聚居地h[j]的临时议事处管理的种族个数。

Sample Input

10
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
5
2
6 1
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8

Sample Output

1 9
3 1 4 1 1
10
1 1 3 5
4 1 3 1 1

HINT

N<=300000, q<=300000,m[1]+m[2]+…+m[q]<=300000


虚树+树DP

构造完虚树以后,对于每个在虚树上的点找到最近的出现在询问的点

然后对于每条链,我们直接划分给控制两个端点的点

然后对于没有出现在链上的点,我们记录每个点的子树大小。用这个大小减去已经分配过的点,剩下的点均分配给控制当前点的那个点

#include<cassert>#include<queue>#include<cstdio>#include<string>#include<cstring>#include<algorithm>using namespace std;struct line{int s,t;long long x;int next;}a[600001],exa[600001];int head[300001],exhead[300001];int edge,exedge;inline void add(int s,int t,long long x){a[edge].next=head[s];head[s]=edge;a[edge].s=s;a[edge].t=t;a[edge].x=x;}inline void exadd(int s,int t,long long x){exa[exedge].next=exhead[s];exhead[s]=exedge;exa[exedge].s=s;exa[exedge].t=t;exa[exedge].x=x;}bool v[300001];int dep[300001];int ans[300001][22];long long anc[300001][22];queue<int> Q,Q1;inline void bfs(int r){     int i,j;     dep[r]=1;     for(i=0;i<=21;i++)          ans[r][i]=r;     while(!Q.empty())          Q.pop();     Q.push(r);     v[r]=true;     while(!Q.empty())     {          int d=Q.front();          Q.pop();          for(i=head[d];i!=0;i=a[i].next)          {               int t=a[i].t;               if(!v[t])               {                    v[t]=true;                    Q.push(t);                    dep[t]=dep[d]+1;                    ans[t][0]=d;                    anc[t][0]=a[i].x;                    int dt;long long dc;                    for(j=1;j<=21;j++)                    {                     dt=ans[t][j-1];                     dc=anc[t][j-1];                         ans[t][j]=ans[dt][j-1];                         dc+=anc[dt][j-1];                         anc[t][j]=dc;                    }               }          }     }}long long ansx;inline int swim(int x,int y){ int i=21;      while(dep[x]!=dep[y])     {          while(dep[ans[y][i]]<dep[x])               i--;          ansx+=anc[y][i];          y=ans[y][i];     }     return y;}inline long long lca(int x,int y){ ansx=0;     if(dep[x]>dep[y])     {          int t=x;          x=y;          y=t;     }     y=swim(x,y);     int i=21;     while(x!=y)     {          while(ans[x][i]==ans[y][i]&&i!=0)               i--;          ansx+=anc[x][i];          ansx+=anc[y][i];          x=ans[x][i];          y=ans[y][i];     }     return x;}int tot;int ld[300001],rd[300001];int son[300001];inline void dfs(int d){tot++;ld[d]=tot;v[d]=true;int i;for(i=head[d];i!=0;i=a[i].next){int t=a[i].t;if(!v[t]){dfs(t);son[d]+=son[t];}}rd[d]=tot;son[d]++;}int poi[300001],stak[300001],poix[300001];bool mark[300001],vx[300001];int rt;inline bool cmp(int x,int y){return ld[x]<ld[y];}inline void create(int k){int i,j,lc;int top=0;top++;stak[top]=poi[1];exedge=0;exhead[poi[1]]=0;for(i=2;i<=k;i++){lc=lca(stak[top],poi[i]);if(lc==stak[top]){exhead[poi[i]]=0;top++;stak[top]=poi[i];if(dep[poi[i]]<dep[rt])rt=poi[i];}else{int tmp=top;while(tmp>0&&dep[stak[tmp]]>dep[lc])tmp--;tmp++;for(j=tmp;j<=top-1;j++){lca(stak[j],stak[j+1]);exedge++;exadd(stak[j],stak[j+1],ansx);exedge++;exadd(stak[j+1],stak[j],ansx);}int pretmp=stak[tmp];if(tmp==0){exhead[lc]=0;top=1;stak[top]=lc;if(dep[lc]<dep[rt])rt=lc;}else if(stak[tmp-1]!=lc){exhead[lc]=0;//tmp++;stak[tmp]=lc;top=tmp;if(dep[lc]<dep[rt])rt=lc;}elsetop=tmp-1;lca(pretmp,lc);exedge++;exadd(pretmp,lc,ansx);exedge++;exadd(lc,pretmp,ansx);exhead[poi[i]]=0;top++;stak[top]=poi[i];if(dep[poi[i]]<dep[rt])rt=poi[i];}}for(i=1;i<=top-1;i++){lca(stak[i],stak[i+1]);exedge++;exadd(stak[i],stak[i+1],ansx);exedge++;exadd(stak[i+1],stak[i],ansx);}}long long d1[300001],ansxx[300001];int d2[300001];int fa[300001];long long fax[300001];inline void trdp(int d,long long dis,int x){ansxx[d]=0;bool flag=false;Q.push(d);Q1.push(d);v[d]=true;d1[d]=dis;d2[d]=x;int i;for(i=exhead[d];i!=0;i=exa[i].next){int t=exa[i].t;if(!v[t]){fa[t]=d;fax[t]=exa[i].x;flag=true;if(mark[d])trdp(t,exa[i].x,d);elsetrdp(t,dis+exa[i].x,x);if(d1[t]+exa[i].x<d1[d]||d1[t]+exa[i].x==d1[d]&&d2[t]<d2[d]){d1[d]=d1[t]+exa[i].x;d2[d]=d2[t];}}}if(mark[d]){d1[d]=0;d2[d]=d;}}inline int jumpx(int x,int y,int xx){ int i=21;  int tar=dep[x]-y; if(tar<dep[xx]) tar=dep[xx]; int sum=0;     while(dep[x]>tar)     {     //  if(x==256&&y==2&&xx==55)      // {     //  int xxx=0;      // }              sum++;      // assert(sum<=200000);       if(sum>100000)        int xxx=0;          while(dep[ans[x][i]]<tar)               i--;          x=ans[x][i];     }     return x;}inline void dfsx(int d){v[d]=true;int i;long long sumx=son[d];bool flag=false;for(i=exhead[d];i!=0;i=exa[i].next){int t=exa[i].t;if(!v[t]){flag=true;dfsx(t);int len=exa[i].x-1;int lxx=jumpx(t,len,d);len+=d1[d]+d1[t];sumx-=son[lxx];if(len%2==0){int lx=jumpx(d2[t],len/2,d);ansxx[d2[d]]+=son[lxx]-son[lx];ansxx[d2[t]]+=son[lx]-son[t];}else{if(d2[d]<d2[t]){int lx=jumpx(d2[t],len/2,d);ansxx[d2[d]]+=son[lxx]-son[lx];ansxx[d2[t]]+=son[lx]-son[t];}else{int lx=jumpx(d2[t],(len+1)/2,d);ansxx[d2[d]]+=son[lxx]-son[lx];ansxx[d2[t]]+=son[lx]-son[t];}}}}ansxx[d2[d]]+=sumx;}inline void getans(int k){dfsx(rt);if(rt!=1)ansxx[d2[rt]]+=son[1]-son[rt];int i;for(i=1;i<=k-1;i++)printf("%lld ",ansxx[poix[i]]);printf("%lld \n",ansxx[poix[i]]);}int main(){//freopen("data.in","r",stdin); //freopen("data.out","w",stdout);int n;scanf("%d",&n);int i,j;int s,t;long long x;for(i=1;i<=n-1;i++){scanf("%d%d",&s,&t);edge++;add(s,t,1);edge++;add(t,s,1);}bfs(1);memset(v,false,sizeof(v));dfs(1);int m,k;scanf("%d",&m);memset(v,false,sizeof(v));memset(vx,false,sizeof(vx));memset(mark,0,sizeof(mark));for(i=1;i<=m;i++){scanf("%d",&k);for(j=1;j<=k;j++){scanf("%d",&poi[j]);poix[j]=poi[j];mark[poi[j]]=1;}sort(poi+1,poi+1+k,cmp);rt=poi[1];create(k);trdp(rt,2100000000,0);fa[rt]=0;while(!Q1.empty()){int d=Q1.front();if((d1[fa[d]]+fax[d]<d1[d]||d1[fa[d]]+fax[d]==d1[d]&&d2[fa[d]]<d2[d])&&d!=rt){d1[d]=d1[fa[d]]+fax[d];d2[d]=d2[fa[d]];}v[Q1.front()]=false;Q1.pop();}getans(k);while(!Q.empty()){v[Q.front()]=false;Q.pop();}for(j=1;j<=k;j++)mark[poi[j]]=0;}return 0;}