• bzoj千题计划255:bzoj3572: [Hnoi2014]世界树


    http://www.lydsy.com/JudgeOnline/problem.php?id=3572

    明显需要构造虚树

    点属于谁管理分三种情况:

    1、属于虚树的点

    2、在虚树上的边上的点

    3、既不属于虚树的点,又不属于虚树上的边的点

    第一种情况:

    先做一遍树形dp,得到子树中距离它最近的点

    再dfs一遍,看看父节点那一块 是否有比它现在的点更近的点

    第二种情况:

    一条边u-->v 如果u和v属于同一点x管理,那么这条边所代表的所有点也都属于x管理

    否则的话,二分一个点tmp,tmp以上的点归管理u的点管理,tmp及tmp以下的点归管理v的点管理

    第三种情况:

    归这个种树的根 的父节点 管理

    第三种情况可以合并到第一种情况中,即用siz[x]表示虚树中一个点x在原树代表多少个点

    开始siz[x]=原树中x的子树大小

    虚树中每加一条边x-->y,若y属于x的子节点中k的子树,就在siz[x]中减去 原树中k的子树大小

    #include<cmath>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    #define N 300001
    
    typedef long long LL;
    
    #define min(x,y) ((x)<(y) ? (x) : (y))
    
    int n,lim;
    int num,id[N];
    int fa[N][19],SIZ[N],prefix[N],dep[N];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0';c=getchar(); }
    }
    
    namespace Original
    {
        int front[N],nxt[N<<1],to[N<<1];
        int tot;
    
        void add(int u,int v)
        {
            to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
            to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
        }    
        
        void dfs(int x)
        {
            id[x]=++num;
            SIZ[x]=1;
            int t;
            for(int i=front[x];i;i=nxt[i])
            {
                t=to[i];
                if(t!=fa[x][0])
                {
                    fa[t][0]=x;
                    dep[t]=dep[x]+1;
                    dfs(t);
                    SIZ[x]+=SIZ[t];
                }
            }
        }        
    
        void multiplication()
        {
            lim=log(n)/log(2);
            for(int i=1;i<=lim;++i)
                for(int j=1;j<=n;++j)
                    fa[j][i]=fa[fa[j][i-1]][i-1];
        }
    
        void Prefix_dfs(int x)
        {
            int t;
            for(int i=front[x];i;i=nxt[i])
            {
                t=to[i];
                if(t!=fa[x][0])
                {
                    prefix[t]=prefix[x]+SIZ[x]-SIZ[t];
                    Prefix_dfs(t);
                }
            }
        }
    
        void main()
        {
            int u,v;
            read(n);
            for(int i=1;i<n;++i)
            {
                read(u); read(v);
                add(u,v);
            }
            dfs(1);
            multiplication();
            Prefix_dfs(1);
            return;
        }
    }
    
    namespace Imaginary
    {
        int cnt,use[N];
            
        int st[N],top;
    
        int tot;
        int front[N],to[N],nxt[N],from[N],val[N];
    
        int bin[N],bin_cnt;
    
        int siz[N];
    
        int mi[N],bl[N];
        int dy[N],ans[N];
    
        bool cmp(int p,int q)
        {
            return id[p]<id[q];
        }
    
        int find_ancestor(int x,int y)
        {
            for(int i=lim;i>=0;--i)
                if(y>=(1<<i))
                {
                    x=fa[x][i];
                    y-=(1<<i);
                }
            return x;
        }
        
        void add(int u,int v,int w)
        {
            to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; val[tot]=w;
            int s=find_ancestor(v,dep[v]-dep[u]-1);
            siz[u]-=SIZ[s];
        }
    
        int get_lca(int x,int y)
        {
            if(id[x]<id[y]) std::swap(x,y);
            for(int i=lim;i>=0;--i)
                if(id[fa[x][i]]>id[y]) x=fa[x][i];
            return fa[x][0];
        }
    
        int get_dis(int u,int v)
        {
            int lca=get_lca(u,v);
            return dep[u]+dep[v]-dep[lca]*2;
        }
    
        void build()
        {
            std::sort(use+1,use+cnt+1,cmp);
            tot=0;
            st[top=1]=1;
            bin[bin_cnt=1]=1;
            siz[1]=SIZ[1];
            int i=1;
            if(use[1]==1) i=2;
            int x,lca;
            for(;i<=cnt;++i)
            {
                x=use[i];
                lca=get_lca(x,st[top]);
                while(id[lca]<id[st[top]])
                {
                    if(id[lca]>=id[st[top-1]])
                    {
                        add(lca,st[top],dep[st[top]]-dep[lca]);
                        if(lca!=st[--top])
                        {
                            st[++top]=lca;
                            siz[lca]+=SIZ[lca];
                            bin[++bin_cnt]=lca;
                        }
                        break;
                    }
                    add(st[top-1],st[top],dep[st[top]]-dep[st[top-1]]);
                    top--;
                }
                st[++top]=x;
                siz[x]+=SIZ[x];
                bin[++bin_cnt]=x;
            }
            while(top>1)
            {
                add(st[top-1],st[top],dep[st[top]]-dep[st[top-1]]);
                top--;
            }
        }
    
        int dfs1(int x)
        {
            int p,d;
            mi[x]=0;
            if(dy[x]) 
            {
                for(int i=front[x];i;i=nxt[i]) dfs1(to[i]);
                bl[x]=x;
                return x;
            }
            for(int i=front[x];i;i=nxt[i])
            {
                p=dfs1(to[i]);
                d=dep[p]-dep[x];
                if(!mi[x] || d<mi[x])
                {
                    mi[x]=d;
                    bl[x]=p;
                }
                else if(d==mi[x] && p<bl[x]) bl[x]=p;
            }
            return bl[x];
        }
    
        int dfs2(int x)
        {
            int t;
            for(int i=front[x];i;i=nxt[i])
            {
                t=to[i];
                if(!dy[t])
                    if(bl[x]!=bl[t])
                    {
                        if(mi[x]+val[i]<mi[t]) 
                        {
                            mi[t]=mi[x]+val[i];
                            bl[t]=bl[x];
                        }    
                        else if(mi[x]+val[i]==mi[t] && bl[x]<bl[t]) bl[t]=bl[x];
                    }
                dfs2(t);
            }
            ans[dy[bl[x]]]+=siz[x];
        }
    
        void belong()
        {
            dfs1(1);
            dfs2(1);
        }
    
        void get_ans()
        {
            int f,s;
            int l,r,mid,tmp,tmp_son;
            int u,v;
            bool equal;
            int up,down;
            for(int i=1;i<=tot;++i)
            {
                u=from[i];
                v=to[i];
                r=dep[v]-dep[u]-1;
                if(!r) continue;
                s=find_ancestor(v,r);
                if(bl[u]==bl[v]) ans[dy[bl[u]]]+=prefix[v]-prefix[s];
                else 
                {
                    tmp=v;
                    l=1;
                    equal=false;
                    while(l<=r)
                    {
                        mid=l+r>>1;
                        f=find_ancestor(v,mid);
                        down=get_dis(f,bl[v]);
                        up=get_dis(f,bl[u]);
                        if(down<up) tmp=f,l=mid+1;
                        else if(down==up) 
                        { 
                            tmp=f; 
                            equal=true; 
                            tmp_son=find_ancestor(v,mid-1);
                            break; 
                        }
                        else r=mid-1;
                    }
                    if(!equal)
                    {
                        ans[dy[bl[v]]]+=prefix[v]-prefix[tmp];
                        ans[dy[bl[u]]]+=prefix[tmp]-prefix[s];
                    }
                    else
                    {
                        ans[dy[bl[v]]]+=prefix[v]-prefix[tmp_son];
                        ans[dy[bl[u]]]+=prefix[tmp]-prefix[s];
                        ans[dy[min(bl[v],bl[u])]]+=prefix[tmp_son]-prefix[tmp];
                    }
                }
            }
            for(int i=1;i<=cnt;++i) printf("%d ",ans[i]);
            printf("
    ");
        }
    
        void clear()
        {
            for(int i=1;i<=bin_cnt;++i)
            {
                front[bin[i]]=0;
                ans[i]=0;
                dy[bin[i]]=0;
                siz[bin[i]]=0;
            }
            tot=0;
        }
        
        void main()
        {
            int m;
            read(m);
            while(m--)
            {
                read(cnt);
                for(int i=1;i<=cnt;++i) 
                {
                    read(use[i]);
                    dy[use[i]]=i;
                }
                build();
                belong();
                get_ans();
                clear();
            }
            return;
        }
    }
                
    int main()
    {
        Original::main();
        Imaginary::main();
        return 0;
    }
  • 相关阅读:
    拦截器实现对用户是否登录及登陆超时的验证
    Spring+Websocket实现消息的推送
    经典 socket通讯 -- 已验证
    Unity编辑器扩展之RequireComponent等详解
    如何理解着色器,渲染管线,光栅化等概念?
    Unity3D研究院编辑器之脚本设置ToolBar及脚本设置顶视图
    Unity3D研究院编辑器之重写Hierarchy的右键菜单
    Unity3D研究院编辑器之自定义默认资源的Inspector面板
    Unity3D研究院之拓展系统自带组件的Inspector视图
    Unity3D研究院之Inspector视图中的get/set使用
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8497215.html
Copyright © 2020-2023  润新知