【洛谷】世界树-虚树/树形DP

版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ https://blog.csdn.net/corsica6/article/details/79952494

传送门:洛谷-世界树


题意

世界树的形态可以用一个数学模型来描述:世界树中有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年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。


数据范围

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


题解

先建一棵树模拟一下,就会发现对于每个点,如果它的子树里都没有议事处,那么肯定归它管,对于它上面的,找到距离恰为和祖先中第一个议事处距离的一半的,判一下标号大小就好了。
那么结合m的提示,我们对于每一次询问建一颗虚树。


代码

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,x,y,h[N],tot,Q,m,dfn,flor;
int head[N],to[N<<1],nxt[N<<1],a[N],b[N],c[N],top;
int d[N],ans[N],f[N][20],sz[N],rem[N];
int id[N],bel[N],s[N],mx; 

inline int read()
{
	char ch=getchar();int x=0,t=1;
	while(ch<'0' || ch>'9') {if(ch=='-') t=-1;ch=getchar();}
	while(ch>='0' && ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*t;
}

inline bool cmp(int x,int y)
{
	return id[x]<id[y];
}

inline int lca(int x,int y)
{
   if(d[x]>d[y]) swap(x,y);
   int t=d[y]-d[x];
   for(register int i=0;(1LL<<i)<=t;i++){
   	   if(t&(1LL<<i)) y=f[y][i];
   }
   for(register int i=flor;i>=0;i--){
   	  if(f[x][i]!=f[y][i]){
   	  	 x=f[x][i];y=f[y][i];
   	  }
   }
   if(x!=y){
   	return f[x][0];
   }else{
   	return x;
   }
}

inline int dis(int x,int y)
{
	return (d[x]+d[y]-2*(d[lca(x,y)])); 
}

inline void lk(int u,int v)
{
	to[++tot]=v;nxt[tot]=head[u];head[u]=tot;
}

inline void dfs(int x,int fa)
{
	int e;sz[x]=1;id[x]=++dfn;
	for(register int i=1;(1LL<<i)<=d[x];i++){
	   f[x][i]=f[f[x][i-1]][i-1]; 
	} 
	for(register int i=head[x];i;i=nxt[i]){
		if(to[i]==fa) continue;
		e=to[i];d[e]=d[x]+1;
		f[e][0]=x;
		dfs(e,x);
	    sz[x]+=sz[e];
	}
	mx=max(mx,d[x]);
}

inline void df(int x)
{
	c[++dfn]=x;rem[x]=sz[x];int e;
	for(register int i=head[x];i;i=nxt[i]){
	    e=to[i];
		df(e);
		if(!bel[e]) continue;
		int t1=dis(bel[e],x),t2=dis(bel[x],x);
		if(((t1==t2)&&bel[e]<bel[x])||(t1<t2)||(!bel[x])) bel[x]=bel[e];
	}
}

inline void dff(int x)
{
	int e;
	for(register int i=head[x];i;i=nxt[i]){
		e=to[i];
		int t1=dis(bel[e],e),t2=dis(bel[x],e);
		if(((t1==t2)&&bel[x]<bel[e])||(t2<t1)||!bel[e]) bel[e]=bel[x];
		dff(e); 
	}
}

inline void solve(int a,int b)
{
     int ct=b,x=b;
	 for(register int i=flor;i>=0;i--){
	 	if(d[f[x][i]]>d[a]){
	 		x=f[x][i];
	 	}
	 }	
	 rem[a]-=sz[x];
	 if(bel[a]==bel[b]){
	 	ans[bel[a]]+=sz[x]-sz[b];
	 }else{
	 	int e;
	 	for(register int i=flor;i>=0;i--){
	 		e=f[ct][i];
			if(d[e]<=d[a]) continue;
	 		int t1=dis(bel[a],e),t2=dis(bel[b],e);
	 		if(((t1==t2)&&(bel[b]<bel[a]))||(t1>t2)) ct=e;
	 	}
	 	ans[bel[a]]+=(sz[x]-sz[ct]);
	 	ans[bel[b]]+=(sz[ct]-sz[b]);
	 }
}

int main(){
	n=read();
	for(register int i=1;i<n;i++){
		int u=read(),v=read();
		lk(u,v);lk(v,u);
	}
	dfs(1,0);
	flor=(int)(log(mx)/log(2));
	if((1LL<<flor)<mx) flor++;
	memset(head,0,sizeof(head));
	Q=read();
	while(Q--){
		dfn=0;top=0;tot=0;
		m=read();
		for(register int i=1;i<=m;i++){
			a[i]=read();b[i]=a[i];
			bel[a[i]]=a[i];
		}
		sort(a+1,a+m+1,cmp);
		if(bel[1]!=1) s[++top]=1;
		for(register int i=1;i<=m;i++){
		   int t=a[i],p=0;
		   while(top>0){
			  p=lca(s[top],t);
			  if(top>1 && d[p]<d[s[top-1]]){
			  	lk(s[top-1],s[top]);top--;
			  }else if(d[p]<d[s[top]]){
			  	lk(p,s[top]);top--;break;
			  }else break;
		   }
		   if(s[top]!=p) s[++top]=p;
		   s[++top]=t;
	     }
	     while(top>1){lk(s[top-1],s[top]);top--;}
		   df(1);dff(1);
		   for(register int i=1;i<=dfn;i++){
		   	for(register int j=head[c[i]];j;j=nxt[j]){
		   		solve(c[i],to[j]);
		   	}
		   }
		   for(register int i=1;i<=dfn;i++) 
		     ans[bel[c[i]]]+=rem[c[i]];
		   for(register int i=1;i<=m;i++) printf("%d ",ans[b[i]]);
		   printf("\n");
		   for(register int i=1;i<=dfn;i++){
		   	  ans[c[i]]=bel[c[i]]=rem[c[i]]=head[c[i]]=0;
		   }
		} 
		return 0;
}

ps:代码参照hzwer

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试