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");
	}
}
posted @ 2020-11-05 22:08  *LZX*  阅读(205)  评论(0编辑  收藏  举报