P3233 [HNOI2014]世界树

这是一道有趣的题!

第一眼:建虚树然后 DP?好麻烦。

第二眼:将临时议事所按照深度排序,接着按顺序从小到大覆盖,傻逼题。

第三眼:怎么判断覆盖的结点当前属于哪个临时议事所啊,这不是要求距离当前临时议事所最近的已经做过的临时议事所吗,我是傻逼。

第四眼:用数据结构维护?码量有点大不想写!

第五眼:在按照深度从小到大排序的同时以编号为第二关键字从小到大排序。这样在虚树上向上跳,遇到没有标记过的结点就标记,标记过的就直接不做了。保证了复杂度,也不用什么数据结构啦。

至于证明,显然排序后到当前临时议事所管辖的一定是向上到某个结点的整个子树。

讲得有点简略,多画图就是了。

时间复杂度 (Oleft(nlog n ight))

code:

#include<bits/stdc++.h>
using namespace std;
#define N 300005
#define NN 600005
#define For(i,x,y)for(i=x;i<=(y);i++)
#define Down(i,x,y)for(i=x;i>=(y);i--)
struct node
{
	int next,to;
}e[NN];
bool type[N];
int fa[N][20],h[NN],head[N],bin[N],last[N],ans[N],dfn[N],col[N],id[N],dep[N],siz[N],g,cnt;
int read()
{
	int A;
	bool K;
	char C;
	C=A=K=0;
	while(C<'0'||C>'9')K|=C=='-',C=getchar();
	while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
	return(K?-A:A);
}
void write(int X)
{
	if(X<0)putchar('-'),X=-X;
	if(X>9)write(X/10);
	putchar(X%10|48);
}
inline void add(int u,int v)
{
	e[++g].to=v;
	e[g].next=head[u];
	head[u]=g;
}
inline bool cmp1(int _,int __)
{
	return dfn[_]<dfn[__];
}
inline bool cmp2(int _,int __)
{
	return(dep[_]==dep[__]?_<__:dep[_]<dep[__]);
}
int lca(int x,int y)
{
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y])x=fa[x][bin[dep[x]-dep[y]]];
	if(x==y)return x;
	int i;
	Down(i,bin[dep[x]],0)
	if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
	return fa[y][0];
}
void dfs(int u)
{
	int i=0,v;
	dep[u]=dep[fa[u][0]]+1;
	dfn[u]=++cnt;
	siz[u]=1;
	while(1<<++i<=dep[u])fa[u][i]=fa[fa[u][i-1]][i-1];
	for(i=head[u];i;i=e[i].next)
	{
		v=e[i].to;
		if(v!=fa[u][0])
		{
			fa[v][0]=u;
			dfs(v);
			siz[u]+=siz[v];
		}
	}
}
inline int calc(int x,int y)
{
	return dep[x]+dep[y]-(dep[lca(x,y)]<<1);
}
int get(int u,int num)
{
	int i;
	Down(i,bin[num],0)
	if(num>=1<<i)u=fa[u][i],num-=1<<i;
	return u;
}
int main()
{
	int n,i,x,y,t,m,j,k,pos,p,q;
	n=read();
	For(i,2,n)
	{
		x=read(),y=read();
		add(x,y),add(y,x);
	}
	t=read();
	dfs(1);
	bin[0]=-1;
	For(i,1,n)bin[i]=bin[i>>1]+1;
	while(t--)
	{
		m=read();
		For(i,1,m)h[i]=id[i]=read(),type[h[i]]=1;
		sort(h+1,h+m+1,cmp1);
		For(i,1,m-1)h[i+m]=lca(h[i],h[i+1]);
		m+=m-1;
		sort(h+1,h+m+1,cmp1);
		m=unique(h+1,h+m+1)-h-1;
		For(i,2,m)last[h[i]]=lca(h[i-1],h[i]);
		sort(h+1,h+m+1,cmp2);
		For(i,1,m)
		if(type[h[i]])
		{
			j=h[i];
			while(j&&!col[j])j=last[j];
			if(!j)
			{
				j=h[i];
				while(j&&!col[j])col[j]=h[i],j=last[j];
				ans[h[i]]=n;
				continue;
			}
			/*cout<<h[i]<<' '<<j<<"!!!
";*/
			k=h[i];
			while(1)
			{
				p=calc(col[j],last[k]),q=calc(h[i],last[k]);
				/*cout<<col[j]<<' '<<h[i]<<' '<<k<<' '<<p<<' '<<q<<"???
";*/
				if(p>q||p==q&&h[i]<col[j])k=last[k];
				else break;
			}
			p=calc(col[j],k),q=calc(h[i],k);
			pos=k;
			/*cout<<col[j]<<' '<<h[i]<<' '<<k<<' '<<p<<' '<<q<<"!!!
";*/
			k=get(k,((p+q-(col[j]<h[i]))>>1)-q);
			ans[col[j]]-=siz[k];
			ans[h[i]]=siz[k];
			j=h[i];
			while(j!=pos)
			{
				/*cout<<j<<' '<<h[i]<<"???
";*/
				col[j]=h[i];
				j=last[j];
			}
			col[j]=h[i];
		}
		For(i,1,m)
		if(id[i])
		{
			write(ans[id[i]]);
			putchar(' ');
			id[i]=0;
		}
		else break;
		For(i,1,m)type[h[i]]=ans[h[i]]=col[h[i]]=last[h[i]]=0;
		putchar('
');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/May-2nd/p/14269632.html