zoukankan      html  css  js  c++  java
  • BZOJ 3572: [Hnoi2014]世界树

    BZOJ 3572: [Hnoi2014]世界树

    标签(空格分隔): OI-BZOJ OI-虚数 OI-树形dp OI-倍增


    Time Limit: 20 Sec
    Memory Limit: 512 MB


    Description

    世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
    世界树的形态可以用一个数学模型来描述:世界树中有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年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。

    Input

    第一行为一个正整数n,表示世界树中种族的个数。
    接下来n-l行,每行两个正整数x,y,表示x聚居地与y聚居地之间有一条长度为1的双
    向道路。接下来一行为一个正整数q,表示国王询问的年数。
    接下来q块,每块两行:
    第i块的第一行为1个正整数m[i],表示第i年授权的临时议事处的个数。
    第i块的第二行为m[i]个正整数h[l]、h[2]、…、h[m[i]],表示被授权为临时议事处的聚居地编号(保证互不相同)。

    Output

    输出包含q行,第i行为m[i]个整数,该行的第j(j=1,2…,,m[i])个数表示第i年被授权的聚居地h[j]的临时议事处管理的种族个数。

    Sample Input

    10

    2 1

    3 2

    4 3

    5 4

    6 1

    7 3

    8 3

    9 4

    10 1

    5

    2

    6 1

    5

    2 7 3 6 9

    1

    8

    4

    8 7 10 3

    5

    2 9 3 5 8
    Sample Output

    1 9

    3 1 4 1 1

    10

    1 1 3 5

    4 1 3 1 1
    HINT

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


    Solution####

    虚树,居然到现在才搞,真的太弱了,参考神牛http://lazycal.logdown.com/posts/202331-bzoj3572
    orz


    Code####

    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    using namespace std;
    #define LL long long
    #define MP(a,b) make_pair(a,b)
    #define PA pair<int,int>
    int read()
    {
    	int s=0,f=1;char ch=getchar();
    	while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    	while('0'<=ch&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    	return s*f;
    }
    const int N=300005;
    int n,m;
    int be[N],bn[N*2],bv[N*2],bl[N*2],bw=1;
    void put(int u,int v,int l)
    {bw++;bn[bw]=be[u];be[u]=bw;bv[bw]=v;bl[bw]=l;}
    int dep[N],dep2[N],siz[N];
    int dfn[N],rank[N],dtot;
    int fa[N][19];
    int h[N],t[N],tot;
    void dfs(int x)
    {
    	dfn[rank[x]=++dtot]=x;
    	siz[x]=1;
    	for(int i=be[x],v;i;i=bn[i])
    	    if(!siz[v=bv[i]])
    	       {fa[v][0]=x;
    	        for(int j=0;fa[v][j+1]=fa[fa[v][j]][j];j++);
    	        dep[v]=dep[x]+bl[i];
    	        dep2[v]=dep[x]+1;
    		    dfs(v);
    	        siz[x]+=siz[v];
    		   }
    }
    int lca(int a,int b)
    {
    	if(dep2[a]<dep2[b])swap(a,b);
    	for(int i=18;i>=0;i--)
    	    if(dep2[fa[a][i]]>=dep2[b])
    	        a=fa[a][i];
    	for(int i=18;i>=0;i--)
    	    if(fa[a][i]!=fa[b][i])
    	        a=fa[a][i],b=fa[b][i];
    	return a==b?a:fa[a][0];
    }
    int jump(int x,int dis)
    {
    	for(int i=18;i>=0;i--)
    	    if(dep[fa[x][i]]>dis)
    	        x=fa[x][i];
    	return x;
    }
    bool cmp(int a,int b)
    {
    	return rank[a]<rank[b];
    }
    int sta[N],top;
    int father[N],ans[N],val[N],hh[N];
    PA md[N];
    int main()
    {
    	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
    	n=read();
    	for(int i=1;i<n;i++)
    	   {int u=read(),v=read();
    	    put(u,v,1);
    	    put(v,u,1);
    	   }
    	dep[0]=dep2[0]=-1;
    	dfs(1);
    	for(int Q=read();Q--;)
    	   {m=read();tot=0;
    	    for(int i=1;i<=m;i++)
    	       {hh[i]=h[i]=read(),
    	        md[h[i]]=MP(0,h[i]);
    		    t[++tot]=h[i];
    		    ans[h[i]]=0;
    		   }
    	    sort(&h[1],&h[m+1],cmp);
    	    top=0;
    	    for(int i=1;i<=m;i++)
    	       {int now=h[i];
    		    if(!top){father[sta[++top]=now]=0;continue;}
    		    int LCA=lca(sta[top],now);
    		    for(;dep[sta[top]]>dep[LCA];top--)
    		        if(dep[sta[top-1]]<=dep[LCA])
    		            father[sta[top]]=LCA;
    		    if(sta[top]!=LCA)
    		       {t[++tot]=LCA;
    		        father[LCA]=sta[top];
    		        md[LCA]=MP(0x3f3f3f3f,0);
    		        sta[++top]=LCA;
    			   }
    			father[now]=sta[top];
    			sta[++top]=now;
    		   }
    		for(int i=1;i<=tot;i++)val[t[i]]=siz[t[i]];
    		sort(&t[1],&t[tot+1],cmp);
    		for(int i=tot;i>1;i--)
    		   {int x=t[i],f=father[x];
    		    md[f]=min(md[f],MP(dep[x]-dep[f]+md[x].first,md[x].second));
    		   }
    		for(int i=2;i<=tot;i++)
    		   {int x=t[i],f=father[x];
    		    md[x]=min(md[x],MP(dep[x]-dep[f]+md[f].first,md[f].second));
    		   }
    		for(int i=1;i<=tot;i++)
    		   {int x=t[i],f=father[x];
    		    if(i==1)
    		       {ans[md[x].second]+=n-siz[x];
    		        continue;
    			   }
    			int u=jump(x,dep[f]);
    			val[f]-=siz[u];
    			if(md[f].second==md[x].second)
    			   {ans[md[f].second]+=siz[u]-siz[x];
    			    continue;
    			   }
    			int mid=jump(x,(md[x].first-md[f].first+dep[x]+dep[f]-(md[x].second<md[f].second))/2);
    			ans[md[f].second]+=siz[u]-siz[mid];
    			ans[md[x].second]+=siz[mid]-siz[x];
    		   }
    		for(int i=1;i<=tot;i++)
    		    ans[md[t[i]].second]+=val[t[i]];
    		for(int i=1;i<=m;i++)
    		    printf("%d ",ans[hh[i]]);printf("
    ");
    	   }
    	//fclose(stdin);
    	//fclose(stdout);
    	return 0;
    }
    
    
    
  • 相关阅读:
    制作自适应布局的模块及框架(转载)
    从今天起开始写博了
    工作中碰到的css问题解决方法
    标题写个什么好呢
    快速编写HTML(Zen conding)
    2013年1月21日记事
    opc 方面研究
    关于 部署方面研究 Visual Studio 2013
    intel AVX指令集
    关于 返回数据类型 后 加& 的作用
  • 原文地址:https://www.cnblogs.com/wuyuhan/p/5521249.html
Copyright © 2011-2022 走看看