zoukankan      html  css  js  c++  java
  • [HNOI2014]世界树

    题目描述

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

    题解

    这题快调死我了。。。

    还是细节掌握的不到位。。。

    前置知识:虚树

    就是我们在处理一颗树的时候,它的节点很多,但我们实际用到的点却很少时,就可以用虚树来处理。

    其实就是保留了需要用的点和它们的LCA,所以节点数是O(n)的。

    建树方法:维护一个栈,一开始只有1节点。

    把所有点按照dfs序排序。

    然后加入一个点,查一下它和栈顶的LCA,如果答案就是栈顶,那么堆栈。

    否则就不停的弹栈,然后弹栈的时候连边,注意最后一次弹栈的时候的连边方式。

    然后把LCA和当前点堆栈。

    注意,为了防止出现自环,要写上。

    1、if(a[i].a==st[top])continue;
    2、if(lca!=st[top])

    然后这道题就是把虚树建出来。

    如果这棵树里的每个点都是关键点就好做了。

    但是里面有LCA点,所以我们对每个LCA点维护立它最近的关键点。

    这个可以两遍dfs求。

    然后找到每一条链,计算这条链的贡献,一条链最多会对两个关键点产生贡献,讨论一下就可以了。

    我太zz分了四种情况讨论。。。

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define N 300009
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    int head[N],deep[N],p[N][20],dfn[N],size[N],dp[N],len[N],tot,tot1,h[N],son[N],dfnn,n,q,m,st[N],top,rbs[N],ans[N],ddf_son[N];
    bool vis[N];
    inline ll rd(){
        ll x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    struct edge{int n,to;}e[N<<1],E[N<<1];
    struct node{
        int a,id;    
        inline bool operator <(const node &b)const{return dfn[a]<dfn[b.a];}
    }a[N];
    inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
    inline void link(int u,int v){E[++tot1].n=h[u];E[tot1].to=v;h[u]=tot1;}
    inline int getlca(int a,int b){
        if(deep[a]<deep[b])swap(a,b);
        for(int i=18;i>=0;--i)if(deep[a]-(1<<i)>=deep[b])a=p[a][i];
        if(a==b)return a;
        for(int i=18;i>=0;--i)if(p[a][i]!=p[b][i])a=p[a][i],b=p[b][i];
        return p[a][0];
    }
    inline int jump(int x,int dep){
        for(int i=18;i>=0;--i)if(dep&(1<<i))x=p[x][i];
        return x;
    } 
    void dfs(int u,int fa){
        dfn[u]=++dfnn; 
        size[u]=1;
        for(int i=1;(1<<i)<=deep[u];++i)p[u][i]=p[p[u][i-1]][i-1];
        for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
            int v=e[i].to;p[v][0]=u;deep[v]=deep[u]+1;
            dfs(v,u); size[u]+=size[v];
        }
    }
    void efs(int u){
        int x=size[u];
        if(vis[u])son[u]=u,len[u]=-1;
        for(int i=h[u];i;i=E[i].n){
            int v=E[i].to;
            efs(v);
            int ha=jump(v,deep[v]-deep[u]-1);    
            x-=size[ha];
            if(!vis[u]){
                if(deep[son[v]]-deep[u]-1<len[u]||(deep[son[v]]-deep[u]-1==len[u]&&son[v]<son[u])){
                    son[u]=son[v];len[u]=deep[son[v]]-deep[u]-1;
                }
            }    
        }
        dp[u]=x; 
    }
    void hfs(int u){
        for(int i=h[u];i;i=E[i].n){
            int v=E[i].to;
            if(!vis[v]){
                if(deep[v]-deep[u]+len[u]<len[v]||(deep[v]-deep[u]+len[u]==len[v]&&son[u]<son[v])){
                    son[v]=son[u];len[v]=deep[v]-deep[u]+len[u];
                }
            }    
            hfs(v);
       }
    }
    void gfs(int u){
        //cout<<u<<" "<<son[u]<<endl;
        if(!vis[u])dp[son[u]]+=dp[u];
        for(int i=h[u];i;i=E[i].n){
            int v=E[i].to;gfs(v);
            int de=jump(v,deep[v]-deep[u]-1);
            if(vis[u]&&vis[v]){
            //    cout<<u<<" "<<v<<endl;
                int gua=deep[v]-deep[u]-1;
                int y=gua>>1;if((gua&1)&&v<u)y++;
                int lca=jump(v,y);
                dp[u]+=size[de]-size[lca];dp[v]+=size[lca]-size[v];
            }
            else if(vis[u]&&!vis[v]){
                if(u==son[v])dp[u]+=size[de]-size[v];
                else{
                    int gua=len[v]+deep[v]-deep[u];
                    int y=gua>>1;if((gua&1)&&u<son[v])y++;
                    int lca=jump(v,deep[v]-deep[u]-y-1); 
                    dp[u]+=size[de]-size[lca];dp[son[v]]+=size[lca]-size[v];
                }
            }
            else if(vis[v]&&!vis[u]){
                if(v==son[u])dp[v]+=size[de]-size[v];
                else{
                    int gua=len[u]+deep[v]-deep[u];
                    int y=gua>>1;if((gua&1)&&v<son[u])y++;
                    int lca=jump(v,y); 
                    dp[v]+=size[lca]-size[v];dp[son[u]]+=size[de]-size[lca];
                }
            }
            else{
                int gua=deep[v]-deep[u]+1+len[u]+len[v];
                int y=gua>>1;if((gua&1)&&son[v]<son[u])y++;
                if(y<=len[v]+1)dp[son[u]]+=size[de]-size[v];
                else if(y>=len[v]+deep[v]-deep[u])dp[son[v]]+=size[de]-size[v];
                else{
                   int lca=jump(v,y-len[v]-1);
                   dp[son[u]]+=size[de]-size[lca];dp[son[v]]+=size[lca]-size[v];
                }
            }
        } 
    }
    int main(){
        n=rd();int u,v;
        for(int i=1;i<n;++i){u=rd();v=rd();add(u,v);add(v,u);} 
        dfs(1,0);
        memset(len,0x3f,sizeof(len));
        q=rd();
        while(q--){
            m=rd();
            for(int i=1;i<=m;++i)a[i].a=rd(),a[i].id=i,vis[a[i].a]=1;
            sort(a+1,a+m+1);
            st[top=1]=1;rbs[++rbs[0]]=1;
            for(int i=1;i<=m;++i){
                if(a[i].a==st[top])continue;
                int lca=getlca(st[top],a[i].a);
                if(lca==st[top]){st[++top]=a[i].a;rbs[++rbs[0]]=a[i].a;continue;}
                while(1){
                    int fi=st[top],se=st[top-1];
                    if(dfn[lca]>=dfn[se]){
                        link(lca,fi);top--;break;
                    }
                    else{link(se,fi);top--;}
                }
                if(lca!=st[top]){
                    st[++top]=lca;rbs[++rbs[0]]=lca;
                }
                st[++top]=a[i].a;rbs[++rbs[0]]=a[i].a;
            }
            while(top>1)link(st[top-1],st[top]),top--;    
            efs(1);hfs(1);gfs(1);
            for(int i=1;i<=m;++i)ans[a[i].id]=dp[a[i].a];
            for(int i=1;i<=m;++i)printf("%d ",ans[i]);puts("");
            tot1=0;
            while(rbs[0]){
               int x=rbs[rbs[0]];
              vis[x]=0,dp[x]=0,len[x]=inf,son[x]=0,h[x]=0,ddf_son[x]=0;rbs[0]--;
            }
        }
        return 0;
    }
  • 相关阅读:
    Java必会之多线程
    第一周JVM核心技术-工具与GC策略
    JVM核心技术(第一篇)
    SpringCloudAlibaba使用seata做分布式事务
    Go中的interface(接口)
    快排与堆排
    优先队列原来不难!带你手写一个
    【LeetCode】557. 反转字符串中的单词 III
    【LeetCode】214. 最短回文串
    【LeetCode】17. 电话号码的字母组合(回溯)
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10299777.html
Copyright © 2011-2022 走看看