zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    JavaWeb工程中url地址的写法
    java.lang.NoClassDefFoundError
    {"aa":null} 如何能转化为 {"aa":{}}
    IDEA遇到项目包后面出现% classes,% lines covered该怎么解决
    union all 关键字的应用(合并两个查询结果集到同一个结果集)
    IDEA中的,让光标回到上一次停留的地方
    克隆指定的分支:git clone -b 分支名仓库地址
    转载:再难也要向前爬-唐雅薇
    MacBook Pro 新手入门
    转载:不是书评 :《我是一只IT小小鸟》
  • 原文地址:https://www.cnblogs.com/May-2nd/p/14269632.html
Copyright © 2011-2022 走看看