CF1280C Jeremy Bearimy

【题意】

求在一棵树上,选取的每一对点之间的路径的和的最大值最小值

【分析】

先考虑最小值:

我们希望每个边出现的次数尽量少,所以考虑u的儿子v子树内有偶数个节点,那么就一定可以内部消化不用走(u,v)

反之如果为偶数,那么(u,v)就不得不走一次

考虑按照这样的方式一定能构造出一组走法

考虑最大值:

每条边能经过的最大次数就是子树的siz和n-子树siz的min

 

【代码】

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int head[maxn],tot;
struct edge
{
    int to,nxt;
    ll v;
}e[maxn<<1];
void add(int x,int y,ll z)
{
    e[++tot].to=y; e[tot].nxt=head[x]; e[tot].v=z; head[x]=tot;
}
int n;
ll ans,siz[maxn],res;
void dfs(int u,int fa)
{
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dfs(to,u);
        siz[u]+=siz[to];
        if(siz[to]&1) ans+=e[i].v;
        res+=min(siz[to],n-siz[to])*e[i].v;
    }
}
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        n<<=1;
        for(int i=1;i<=n;i++) head[i]=siz[i]=0;
        tot=0;
        int x,y; ll z;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%lld",&x,&y,&z);
            add(x,y,z); add(y,x,z);
        }
        ans=0; res=0;
        dfs(1,0);
        printf("%lld %lld\n",ans,res);
    }
    return 0;
}

 

posted @ 2021-10-17 21:20  andyc_03  阅读(32)  评论(0编辑  收藏  举报