[HNOI2014]世界树
题目描述
世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
世界树的形态可以用一个数学模型来描述:世界树中有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年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。
题解
这题快调死我了。。。
还是细节掌握的不到位。。。
前置知识:虚树
就是我们在处理一颗树的时候,它的节点很多,但我们实际用到的点却很少时,就可以用虚树来处理。
其实就是保留了需要用的点和它们的LCA,所以节点数是O(n)的。
建树方法:维护一个栈,一开始只有1节点。
把所有点按照dfs序排序。
然后加入一个点,查一下它和栈顶的LCA,如果答案就是栈顶,那么堆栈。
否则就不停的弹栈,然后弹栈的时候连边,注意最后一次弹栈的时候的连边方式。
然后把LCA和当前点堆栈。
注意,为了防止出现自环,要写上。
1、if(a[i].a==st[top])continue; 2、if(lca!=st[top])
然后这道题就是把虚树建出来。
如果这棵树里的每个点都是关键点就好做了。
但是里面有LCA点,所以我们对每个LCA点维护立它最近的关键点。
这个可以两遍dfs求。
然后找到每一条链,计算这条链的贡献,一条链最多会对两个关键点产生贡献,讨论一下就可以了。
我太zz分了四种情况讨论。。。
代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define N 300009 #define inf 0x3f3f3f3f using namespace std; typedef long long ll; int head[N],deep[N],p[N][20],dfn[N],size[N],dp[N],len[N],tot,tot1,h[N],son[N],dfnn,n,q,m,st[N],top,rbs[N],ans[N],ddf_son[N]; bool vis[N]; inline ll rd(){ ll x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } struct edge{int n,to;}e[N<<1],E[N<<1]; struct node{ int a,id; inline bool operator <(const node &b)const{return dfn[a]<dfn[b.a];} }a[N]; inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;} inline void link(int u,int v){E[++tot1].n=h[u];E[tot1].to=v;h[u]=tot1;} inline int getlca(int a,int b){ if(deep[a]<deep[b])swap(a,b); for(int i=18;i>=0;--i)if(deep[a]-(1<<i)>=deep[b])a=p[a][i]; if(a==b)return a; for(int i=18;i>=0;--i)if(p[a][i]!=p[b][i])a=p[a][i],b=p[b][i]; return p[a][0]; } inline int jump(int x,int dep){ for(int i=18;i>=0;--i)if(dep&(1<<i))x=p[x][i]; return x; } void dfs(int u,int fa){ dfn[u]=++dfnn; size[u]=1; for(int i=1;(1<<i)<=deep[u];++i)p[u][i]=p[p[u][i-1]][i-1]; for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){ int v=e[i].to;p[v][0]=u;deep[v]=deep[u]+1; dfs(v,u); size[u]+=size[v]; } } void efs(int u){ int x=size[u]; if(vis[u])son[u]=u,len[u]=-1; for(int i=h[u];i;i=E[i].n){ int v=E[i].to; efs(v); int ha=jump(v,deep[v]-deep[u]-1); x-=size[ha]; if(!vis[u]){ if(deep[son[v]]-deep[u]-1<len[u]||(deep[son[v]]-deep[u]-1==len[u]&&son[v]<son[u])){ son[u]=son[v];len[u]=deep[son[v]]-deep[u]-1; } } } dp[u]=x; } void hfs(int u){ for(int i=h[u];i;i=E[i].n){ int v=E[i].to; if(!vis[v]){ if(deep[v]-deep[u]+len[u]<len[v]||(deep[v]-deep[u]+len[u]==len[v]&&son[u]<son[v])){ son[v]=son[u];len[v]=deep[v]-deep[u]+len[u]; } } hfs(v); } } void gfs(int u){ //cout<<u<<" "<<son[u]<<endl; if(!vis[u])dp[son[u]]+=dp[u]; for(int i=h[u];i;i=E[i].n){ int v=E[i].to;gfs(v); int de=jump(v,deep[v]-deep[u]-1); if(vis[u]&&vis[v]){ // cout<<u<<" "<<v<<endl; int gua=deep[v]-deep[u]-1; int y=gua>>1;if((gua&1)&&v<u)y++; int lca=jump(v,y); dp[u]+=size[de]-size[lca];dp[v]+=size[lca]-size[v]; } else if(vis[u]&&!vis[v]){ if(u==son[v])dp[u]+=size[de]-size[v]; else{ int gua=len[v]+deep[v]-deep[u]; int y=gua>>1;if((gua&1)&&u<son[v])y++; int lca=jump(v,deep[v]-deep[u]-y-1); dp[u]+=size[de]-size[lca];dp[son[v]]+=size[lca]-size[v]; } } else if(vis[v]&&!vis[u]){ if(v==son[u])dp[v]+=size[de]-size[v]; else{ int gua=len[u]+deep[v]-deep[u]; int y=gua>>1;if((gua&1)&&v<son[u])y++; int lca=jump(v,y); dp[v]+=size[lca]-size[v];dp[son[u]]+=size[de]-size[lca]; } } else{ int gua=deep[v]-deep[u]+1+len[u]+len[v]; int y=gua>>1;if((gua&1)&&son[v]<son[u])y++; if(y<=len[v]+1)dp[son[u]]+=size[de]-size[v]; else if(y>=len[v]+deep[v]-deep[u])dp[son[v]]+=size[de]-size[v]; else{ int lca=jump(v,y-len[v]-1); dp[son[u]]+=size[de]-size[lca];dp[son[v]]+=size[lca]-size[v]; } } } } int main(){ n=rd();int u,v; for(int i=1;i<n;++i){u=rd();v=rd();add(u,v);add(v,u);} dfs(1,0); memset(len,0x3f,sizeof(len)); q=rd(); while(q--){ m=rd(); for(int i=1;i<=m;++i)a[i].a=rd(),a[i].id=i,vis[a[i].a]=1; sort(a+1,a+m+1); st[top=1]=1;rbs[++rbs[0]]=1; for(int i=1;i<=m;++i){ if(a[i].a==st[top])continue; int lca=getlca(st[top],a[i].a); if(lca==st[top]){st[++top]=a[i].a;rbs[++rbs[0]]=a[i].a;continue;} while(1){ int fi=st[top],se=st[top-1]; if(dfn[lca]>=dfn[se]){ link(lca,fi);top--;break; } else{link(se,fi);top--;} } if(lca!=st[top]){ st[++top]=lca;rbs[++rbs[0]]=lca; } st[++top]=a[i].a;rbs[++rbs[0]]=a[i].a; } while(top>1)link(st[top-1],st[top]),top--; efs(1);hfs(1);gfs(1); for(int i=1;i<=m;++i)ans[a[i].id]=dp[a[i].a]; for(int i=1;i<=m;++i)printf("%d ",ans[i]);puts(""); tot1=0; while(rbs[0]){ int x=rbs[rbs[0]]; vis[x]=0,dp[x]=0,len[x]=inf,son[x]=0,h[x]=0,ddf_son[x]=0;rbs[0]--; } } return 0; }