• hdu 6567 树形dp+树的重心


    题意

    给n个点,以及n-2条边,意思是给出两棵树,找到两个点连接,使得这棵树上的每个点到另一个点的经过的边的之和为最小值

    题解

    根据自己的数据1-2 2-3 4-5 5-6可以得出求两个树的重心连接,然后树形dp直接得出答案,先用并查集得出两个树的点数和归属,然后连成一棵树,然后用边权算贡献==子节点*其余的节点数之和

    树的重心模板

    void dfs1(int r){
        vis[r]=1;
        sz[r]=1;
        int tmp=0;
        for(int i=head[r];~i;i=edge[i].next){
            int v=edge[i].to;
            if(!vis[v]){
                dfs1(v);sz[r]+=sz[v];
                tmp=max(tmp,sz[v]);
            }
        }
        tmp=max(tmp,n1-sz[r]);
        if(tmp<sz0){
            zx1=r;
            sz0=tmp;
        }
    }
    

    ac代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define il inline
    #define it register int
    #define inf 0x3f3f3f3f
    #define lowbit(x) (x)&(-x)
    #define pii pair<int,int>
    #define mak(a,b) make_pair(a,b)
    #define mem(a,b) memset(a,b,sizeof(a))
    #define mod 1000000007
    const double pi=acos(-1.0);
    const int N=1e5+10;
    int F[N],ge[N];
    int findd(int x){return F[x]==x?x:F[x]=findd(F[x]);}
    int sz[N],zx1,zx2,head[N],tot,n,n1,n2,vis[N],sz2[N],sz0;
    ll ans;
    struct{
        int to,next;
    }edge[N*2];
    void add(int u,int v){
        edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;
        edge[tot].to=u;edge[tot].next=head[v];head[v]=tot++;
    }
    void inint(){
        mem(head,-1);tot=0;
        for(int i=1;i<=n;i++){
            F[i]=i;ge[i]=1;
        }
        zx1=-1,zx2=-1;ans=0;
    }
    void dfs1(int r){
        vis[r]=1;
        sz[r]=1;int tmp=0;
        for(int i=head[r];~i;i=edge[i].next){
            int v=edge[i].to;
            if(!vis[v]){
                dfs1(v);sz[r]+=sz[v];
                tmp=max(tmp,sz[v]);
            }
        }
        tmp=max(tmp,n1-sz[r]);
        if(tmp<sz0){
            zx1=r;
            sz0=tmp;
        }
    }
    void dfs2(int r){
        vis[r]=1;
        sz[r]=1;int tmp=0;
        for(int i=head[r];~i;i=edge[i].next){
            int v=edge[i].to;
            if(!vis[v]){
                dfs2(v);sz[r]+=sz[v];
                tmp=max(tmp,sz[v]);
            }
        }
        tmp=max(tmp,n2-sz[r]);
        if(tmp<sz0){
            zx2=r;
            sz0=tmp;
        }
    }
    void dfs(int u,int fa){
        sz[u]=1;
        for(int i=head[u];~i;i=edge[i].next){
            int v=edge[i].to;if(fa==v){continue;}
            dfs(v,u);
            sz[u]+=sz[v];
        }
        for(int i=head[u];~i;i=edge[i].next){
             int v=edge[i].to;if(fa==v){continue;}
             ans+=(ll)(n-sz[v])*sz[v];
        }
    }
    int main(){
        while(~scanf("%d",&n)){
            inint();
            for(int i=0;i<n-2;i++){
                int u,v;scanf("%d%d",&u,&v);add(u,v);
                int uu=findd(u),vv=findd(v);
                if(uu!=vv){
                    F[uu]=vv;ge[vv]+=ge[uu];
                }
            }
            int s1=-1,s2;
            for(int i=1;i<=n;i++){
                if(F[i]==i && s1==-1){
                    s1=i;n1=ge[i];
                }
                else if(F[i]==i && s1!=-1){
                    s2=i;n2=ge[i];
                }
            }
            mem(vis,0);sz0=inf;
            dfs1(s1);
            mem(vis,0);sz0=inf;
            dfs2(s2);//cout<<zx1<<zx2<<endl;
            add(zx1,zx2);
            dfs(1,0);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Codeforces Round #281 (Div. 2) A. Vasya and Football(模拟)
    自动生成代码工具
    导入导出维护计划
    收集错误日志方法
    C#常用控件和属性
    人民币转换
    身份证验证
    设置下拉列表项的默认值
    清除维护任务
    清除MSSQL历史记录
  • 原文地址:https://www.cnblogs.com/luoyugongxi/p/13748779.html
Copyright © 2020-2023  润新知