zoukankan      html  css  js  c++  java
  • 【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站

    Description

    Input

    第一行为N,1<N<=50000,表示树的节点数目,树的节点从1到N编号。
    接下来N-1行,每行两个整数U,V,表示U与V之间有一条边。
    再接下N行,每行一个正整数,其中第i行的正整数表示编号为i的节点权值为W(I),树的深度<=100

    Output

    将最小的S(x,y)输出,结果保证不超过19^9

    Sample Input

    5
    1 2
    1 3
    3 4
    3 5
    5
    7
    6
    5
    4

    Sample Output

    14

    HINT

    选取两个中心节点为2,3

    —————————————————————————————

    这道题很像树的重心只不过这里要求的重心有两个QAQ

    考虑树的深度比较小 我们正常求树的重心的方法就是树的高度h

    这样算下来我们因为要求两个重心 那么我们可以O(n)枚举一条边把树变成两个

    再O(h)算答案 这样复杂度是可以接受的

    注意我们本来的sz指的是子树内的权值和

    枚举两个点之后两棵树一开始的重心默认为1棵 是1 1棵是u

    然后在贪心往下找 

    当然这样可能会有问题那就是因为算的是min(dis[x][u],dis[x][v])

    这样的话我们本来是贪心树里面的到这个点 但是这样肯定会错

    这样的话其实也影响答案 因为这个只会使当前解比真实解大

    最优解的情况是不会受影响的 这样就可以解决这道问题辣

    tips sum+=sz[x](x->2-n)

    这样其实就是在算路径和 这个转换使代码异常优美2333

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    using std::min;
    using std::swap;
    const int M=1e5+7;
    const LL inf=0x3f3f3f3f;
    char buf[M*33],*ptr=buf-1;
    int read(){
        int ans=0,f=1,c=*++ptr;
        while(c<'0'||c>'9'){if(c=='-') f=-1; c=*++ptr;}
        while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=*++ptr;}
        return ans*f;
    }
    LL ans=inf,sz[M],mx[M],sec[M],sum,w[M];
    int T,n,fa[M],dep[M];
    int first[M],cnt;
    struct node{int from,to,next;}e[2*M];
    void ins(int a,int b){e[++cnt]=(node){a,b,first[a]}; first[a]=cnt;}
    void insert(int a,int b){ins(a,b); ins(b,a);}
    void dfs(int x,int f){
        sz[x]=w[x]; mx[x]=sec[x]=0;
        for(int i=first[x];i;i=e[i].next){
            int now=e[i].to;
            if(now==f) continue;
            fa[now]=x; dep[now]=dep[x]+1;
            dfs(now,x); sz[x]+=sz[now];
            if(sz[now]>sz[mx[x]]) sec[x]=mx[x],mx[x]=now;
            else if(sz[now]>sz[sec[x]]) sec[x]=now;
        }
    }
    int main(){
        fread(buf,1,sizeof(buf),stdin);
        int x,y;
        n=read();
        for(int i=1;i<n;i++) x=read(),y=read(),insert(x,y);
        for(int i=1;i<=n;i++) w[i]=read();
        dep[1]=1; dfs(1,-1);
        sum=0; for(int i=2;i<=n;i++) sum+=sz[i];
        for(int i=1;i<=cnt;i+=2){
            int u=e[i].from,v=e[i].to;
            if(dep[u]<dep[v]) swap(u,v);
            LL nowh=sum;
            for(x=v;x;x=fa[x]) sz[x]-=sz[u],nowh-=sz[u];
            x=1;
            while(1){
                if(sz[mx[x]]>sz[sec[x]]&&mx[x]!=u) y=mx[x];
                else y=sec[x];
                if(sz[y]*2>sz[1]) x=y,nowh=nowh-sz[y]*2+sz[1];
                else break;
            }
            x=u;
            while(1){
                if(sz[mx[x]]*2>sz[u]) nowh=nowh-sz[mx[x]]*2+sz[u],x=mx[x];
                else break;
            }
            ans=min(ans,nowh);
            for(x=v;x;x=fa[x]) sz[x]+=sz[u];
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    命令行标签
    ts关键还是js 因为要编译成js
    nuxt axios
    vuecli3-ssr
    v-text
    这样竟然也可以水平居中 两个属性都必须
    纯CSS实现垂直居中的几种方法
    下图片异步变同步
    [Java] 扯淡系列_找工作流程 与 注意问题
    [Java] Spring3.0 Annotation
  • 原文地址:https://www.cnblogs.com/lyzuikeai/p/7598526.html
Copyright © 2011-2022 走看看