码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-03-03 19:29:46      阅读:125      评论:0      收藏:0      [点我收藏+]

标签:构造   ios   bool   name   需要   amp   val   clu   bin   

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("\n");
    }

    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;
}

 

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

标签:构造   ios   bool   name   需要   amp   val   clu   bin   

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8497215.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!