博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

「BZOJ1827」奶牛大集会

题意:找一个点x使得$\sum c_i\cdot dis(i,x)$最小(其中dis表示i->x的距离)

做法:先跑出一个点的答案,然后在树上跳动,x->son的时候son这棵子树的答案都减去$\sum c_i*dis(x,son),i\in son$,其他节点都增加$\sum c_i*dis(x,son)$

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read() {
    ll x=0,f=1; char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())
        if(ch=='-')f=-f;
    for(;ch>='0'&&ch<='9';ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
inline void chkmin( int &a,int b ) { if(a>b) a=b; }
inline void chkmax( int &a,int b ) { if(a<b) a=b; }
#define _ read()
#define ln endl
const int N=1e5+5;
int cnt,head[N];
struct Edge { int to,nxt,w; } e[N<<1];
inline void insert( int u,int v,int w ) {
    e[++cnt]=(Edge) { v,head[u],w } ;
    head[u]=cnt;
}
inline void ins( int u,int v,int w ) {
    insert(u,v,w);
    insert(v,u,w);
}
ll sum[N],ans,tot,res;
int a[N],n;
inline void dfs_1( int x,int fa ) {
    sum[x]=a[x];
    for( int i=head[x];i;i=e[i].nxt ) {
        if(e[i].to!=fa) {
            dfs_1(e[i].to,x);
            sum[x]+=sum[e[i].to];
            ans+=e[i].w*sum[e[i].to];
        }
    }
}
inline void dfs_2( int x,int fa ) {
    res=min(res,ans);
    for( int i=head[x];i;i=e[i].nxt ) {
        if(e[i].to!=fa) { 
            ans+=(tot-sum[e[i].to])*e[i].w; ans-=e[i].w*sum[e[i].to];
            dfs_2(e[i].to,x);
            ans-=(tot-sum[e[i].to])*e[i].w; ans+=e[i].w*sum[e[i].to];
        }
    }
}
int main() {
    n=_;
    for( int i=1;i<=n;i++ ) a[i]=_,tot+=a[i];
    for( int i=1;i<n;i++ ) {
        int u=_,v=_,w=_;
        ins(u,v,w);
    }
    dfs_1(1,0); res=ans;
    // cout<<sum[3]<<ln;
    // cout<<ans<<ln;
    dfs_2(1,0);
    cout<<res<<ln;
}
「BZOJ1827」奶牛大集会

 

posted @ 2019-08-08 09:09  gllonkxc  阅读(167)  评论(0编辑  收藏  举报