• bzoj3572: [Hnoi2014]世界树


    首先先套路上虚树

    对于虚树,分成两类点:一种是作为议事处的,一种是虚树加的lca

    如果树上没有加的点,对于两个议事处之间的路径,一半归下面,一半归上面,这个就很好解决了

    对于lca,我们需要找到在树上离它最近的议事处,此时lca相当于帮这个议事处去和其他的点分配路径上的点

    这个我们用二次扫描+换根法就可以弄出来

    说得轻巧码量巨大

    叫我AK·再做数据结构我是狗·C·真香·qhzdy

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    struct node
    {
        int x,y,next;
    }a[610000];int len,last[310000];
    void ins(int x,int y)
    {
        len++;
        a[len].x=x;a[len].y=y;
        a[len].next=last[x];last[x]=len;
    }
    int z,ys[310000];
    int Bin[30],f[30][310000],dep[310000],tot[310000];
    void dfs(int x)
    {
        ys[x]=++z; tot[x]=1;
        for(int i=1;Bin[i]<=dep[x];i++)f[i][x]=f[i-1][f[i-1][x]];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=f[0][x])
            {
                f[0][y]=x;
                dep[y]=dep[x]+1;
                dfs(y);
                tot[x]+=tot[y];
            }
        }
    }
    int LCA(int x,int y)
    {
        if(dep[x]<dep[y])swap(x,y);
        for(int i=25;i>=0;i--)
            if(dep[x]-dep[y]>=Bin[i])x=f[i][x];
        if(x==y)return x;
        
        for(int i=25;i>=0;i--)
            if(dep[x]>=Bin[i]&&f[i][x]!=f[i][y])x=f[i][x],y=f[i][y];
        return f[0][x];
    }
    int findkth(int x,int k)
    {
        for(int i=25;i>=0;i--)
            if(k>=Bin[i])x=f[i][x],k-=Bin[i];
        return x;
    }
    
    //---------------------------------------init-----------------------------------------------------------
    
    int c[310000];
    
    int h[310000],h2[310000];
    bool cmp(int h1,int h2){return ys[h1]<ys[h2];}
    
    node e[610000];int elen,elast[310000];
    void eins(int x,int y)
    {
        elen++;
        e[elen].x=x;e[elen].y=y;
        e[elen].next=elast[x];elast[x]=elen;
    }
    ///~~~~~~~~~~~~边目录~~~~~~~~~~~~~~~~~~
    
    int top,sta[310000];bool islca[310000];
    void VirtualTree(int m)
    {
        sort(h+1,h+m+1,cmp);
        
        top=0;sta[++top]=1;
        for(int i=1;i<=m;i++)
        {
            int lca=LCA(h[i],sta[top]);
            while(1)
            {
                if(dep[lca]>=dep[sta[top-1]]&&lca!=sta[top-1]&&lca!=sta[top])
                {
                    eins(lca,sta[top]);top--;
                    sta[++top]=lca;
                    break;
                }
                if(lca==sta[top])break;
                bool bk=(lca==sta[top-1]);
                if(top>1)
                    eins(sta[top-1],sta[top]),top--;
                if(bk)break;
            }
            if(h[i]!=sta[top])sta[++top]=h[i];
            islca[h[i]]=false;
        }
        while(top>1)
            eins(sta[top-1],sta[top]),top--;
    }
    
    //--------------------------------------composition-----------------------------------------------------------
    
    int p[2][310000],dis[2][310000],hp[310000],hd[310000];
    
    int d1,d2;
    bool check(int x,int y,int w)
    {
        if(y==-1)return false;
        if(p[w][x]==-1)return true;
        return d1==d2?p[w][x]>y:d1>d2;
    }
    //~~~~~~~~~~~烦人的check~~~~~~~~~~~~~
    
    void solvert(int x,int fr)
    {
        p[0][x]=p[1][x]=-1;
        if(!islca[x])p[0][x]=x,dis[0][x]=0;
        for(int k=elast[x];k;k=e[k].next)
        {
            int y=e[k].y;
            if(y!=fr)
            {
                solvert(y,x);
                
                bool bk=false;
                d1=dis[0][x],d2=dis[0][y]+dep[y]-dep[x];
                if(check(x,p[0][y],0))
                {
                    bk=true;
                    p[0][x]=p[0][y], dis[0][x]=d2;
                    
                    d1=dis[1][x],d2=dis[1][y]+dep[y]-dep[x];
                    if(check(x,p[1][y],1))
                        p[1][x]=p[1][y], dis[1][x]=d2;
                }
                d1=dis[1][x],d2=dis[0][y]+dep[y]-dep[x];
                if(!bk&&check(x,p[0][y],1))
                    p[1][x]=p[0][y], dis[1][x]=d2;
            }
        }
    }
    void changert(int x,int fr)
    {
        hp[x]=p[0][x],hd[x]=dis[0][x];
        for(int k=elast[x];k;k=e[k].next)
        {
            int y=e[k].y;
            if(y!=fr)
            {
                if(p[0][x]==p[0][y])
                {
                    d1=dis[0][y],d2=dis[1][x]+dep[y]-dep[x];
                    if(check(y,p[1][x],0))
                        p[0][y]=p[1][x], dis[0][y]=d2;
                }
                else 
                {
                    d1=dis[0][y],d2=dis[0][x]+dep[y]-dep[x];
                    if(check(y,p[0][x],0))
                        p[0][y]=p[0][x], dis[0][y]=d2;
                }
                changert(y,x);
            }
        }
    }
    
    //--------------------------------------换根inithp-----------------------------------------------------------
    
    void calc(int x,int y)
    {
        if(hp[x]==hp[y])
        {
            int yy=findkth(y,dep[y]-dep[x]-1);
            c[hp[x]]+=tot[yy]-tot[y];
        }
        else
        {
            int pt=dep[y]-dep[x]-1+hd[x]+hd[y];        
            int xx=findkth(y,dep[y]-dep[x]-1);
            int yy=findkth(y,pt/2+((pt%2==1)?(hp[y]<hp[x]):0)-hd[y]);
                
            c[hp[x]]+=tot[xx]-tot[yy];
            c[hp[y]]+=tot[yy]-tot[y];
        }
    }
    void solve(int x,int fr)
    {
        c[hp[x]]+=tot[x];
        for(int k=elast[x];k;k=e[k].next)
        {
            int y=e[k].y;
            if(y!=fr)
            {
                c[hp[x]]-=tot[findkth(y,dep[y]-dep[x]-1)];
                calc(x,y);
                solve(y,x);
            }
        }
        elast[x]=0;
        islca[x]=true;
        hp[x]=hd[x]=-1;
    }
    
    //---------------------------------------------solve---------------------------------------------------------
    
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        int n,x,y;
        scanf("%d",&n);
        len=0;memset(last,0,sizeof(last));
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            ins(x,y),ins(y,x);
        }
        Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2;
        dep[1]=0;dfs(1);
        
        int Q,m;
        scanf("%d",&Q);
        memset(hp,-1,sizeof(hp));
        memset(islca,true,sizeof(islca));
        while(Q--)
        {
            scanf("%d",&m);
            for(int i=1;i<=m;i++)
                scanf("%d",&h[i]),h2[i]=h[i];
            VirtualTree(m);
            
            solvert(1,0);
            changert(1,0);
            
            solve(1,0);elen=0;
            for(int i=1;i<m;i++)printf("%d ",c[h2[i]]),c[h2[i]]=0;
            printf("%d
    ",c[h2[m]]),c[h2[m]]=0;
     }
        return 0;
    }
  • 相关阅读:
    CSS中关于BFC的背后原理是什么
    CSS中浏览器是怎样解析CSS选择器的?
    JavaScript中关于 == 和 === 的区别是什么?
    JavaScript中关于继承的实现方式
    Vue双向绑定原理
    Node之TinyPNG图片无限次数压缩
    React的生命周期示意图
    Image-webp探究
    JavaScript中关于事件的循环机制
    vue导航点击切换 1.0
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10207028.html
Copyright © 2020-2023  润新知