zoukankan      html  css  js  c++  java
  • CSP2019树的重心

    题解:

    CSP2019D2T3

    首先我们要明确一个性质,那就是对于一棵树的任何一个节点来说,如果这个点不是重心,那么这棵树的重心就一定在这个节点的以重儿子为根节点的子树里

    证明显而易见,因为该点不是重心所以siz[重儿子]一定大于$lfloor frac{siz[x]}{2} floor$

    另外还有一个重心的定义:重心所有子树的大小一定小于等于$lfloor frac{siz[重心]}{2} floor$

    我们首先遍历整棵树,切断一条边(u,v)后,我们得到以u为根、以v为根的两颗树

    然后不断向重儿子跳,直到找到重心

    这里我们可以用倍增实现,时间复杂度$O(N log_{2} N)$

    我们预处理倍增数组fv[x][i],然后对于以v为根的子树,直接倍增找重儿子即可

    对于以u为根的子树,也可以用类似的方法解决,我们只需要让u的父亲变成u的儿子,即f[fa]=u,hv[u][0]=siz[hv[u][0]]<siz[fa]-siz[u]?fa:hv[u][0],然后就好了

    其实这个题还蛮难的 

    CODE:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define dwn(i,a,b) for(int i=a;i>=b;i--)
    #define MAXN 300004
    using namespace std;
    typedef long long ll;
    ll ans;
    int T,n,tot,nxt[MAXN<<1],to[MAXN<<1],fir[MAXN],hv[MAXN][20],f[MAXN],siz[MAXN],shv[MAXN],thv[MAXN],tsiz[MAXN],S;
    int read(){
        int x=0,f=1;
        char ch=getchar();
        while('0'>ch || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while('0'<=ch && ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
        return x*f;
    }
    void ade(int x,int y){
        to[++tot]=y;
        nxt[tot]=fir[x];
        fir[x]=tot;
    }
    void dfs1(int x,int fa){
        f[x]=fa; hv[x][0]=shv[x]=thv[x]=0; tsiz[x]=1;
        for(int k=fir[x];k;k=nxt[k]){
            if(to[k]==fa) continue;
            dfs1(to[k],x);
            tsiz[x]+=tsiz[to[k]];
            if(tsiz[to[k]]>tsiz[thv[x]]) shv[x]=thv[x],thv[x]=to[k];
            else if(tsiz[to[k]]>tsiz[shv[x]]) shv[x]=to[k];
        }
        hv[x][0]=thv[x]; siz[x]=tsiz[x];
    }
    void init(){
        rep(i,1,19) rep(j,1,n) hv[j][i]=hv[hv[j][i-1]][i-1];
    }
    bool chk(int x,int y){
        if(!x) return 0;
        return ((max(siz[hv[x][0]],y-siz[x])*2)<=y);
    }
    void recalc(int x){
        rep(i,1,19) hv[x][i]=hv[hv[x][i-1]][i-1];
    } 
    void clear(){
        memset(fir,0,sizeof(fir));
        tot=ans=0;
    }
    void dfs2(int x,int y){
        int now;
        for(int k=fir[x];k;k=nxt[k]){
            if(to[k]==y) continue;
            if(to[k]==thv[x]) hv[x][0]=shv[x];
            else hv[x][0]=thv[x];
            if(siz[y]>siz[hv[x][0]]) hv[x][0]=y;
            recalc(x);
            siz[to[k]]=tsiz[to[k]]; siz[x]=S-tsiz[to[k]];
            now=x;
            dwn(i,19,0) if(hv[now][i] && siz[x]-siz[hv[now][i]]<=(siz[x]/2)) now=hv[now][i];
        //    cout<<x<<" "<<now<<"FDF"<<" "<<f[now]<<" "<<f[now]*chk(f[now],siz[x])<<endl;
            ans=ans+now*chk(now,siz[x])+f[now]*chk(f[now],siz[x]);
            now=to[k];
            dwn(i,19,0) if(hv[now][i] && siz[to[k]]-siz[hv[now][i]]<=(siz[to[k]]/2)) now=hv[now][i];
            ans=ans+now*chk(now,siz[to[k]])+f[now]*chk(f[now],siz[to[k]]);
            f[x]=to[k];
            dfs2(to[k],x);
        }
        siz[x]=tsiz[x]; hv[x][0]=thv[x]; f[x]=y;
        recalc(x);
        
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            clear();
            rep(i,1,n-1){
                int x=read(),y=read();
                ade(x,y);
                ade(y,x);
            }
            dfs1(1,0);
            init();
            S=tsiz[1];
            dfs2(1,0); 
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    lanya
    Apple watch ,小米微信通知
    jenkins grunt 自动构建流程
    刷机步骤
    ipad忘记了锁屏密码,已经越狱了
    ar
    如何在ubuntu中安装php
    阿里云
    docker swarm 集群及可视化界面的安装及配置
    https://github.com/gaoyangxiaozhu/DockerVI
  • 原文地址:https://www.cnblogs.com/handsome-zlk/p/13780591.html
Copyright © 2011-2022 走看看