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; }