Edge to the Root
题意是给出一个棵树,每条边权都为1,要求在点1和点x之间连一条边,使得连边之后,点1到所有点的路径长度之和最小。
输出最小长度之和。
显然对于一棵树,添一条边之后,形成了一个环,一个在1-x的路径上的环,这个环的形成只对环上的点以及他们的子树上的点的距离产生了影响。 更准确地说,是对环的中点一下的点及子树产生了影响。
cnt数组记录每个点的子树大小+1(加上自己)。
假设环上的点存在cycle数组中,下标从0开始,中点下标为half,共有tot个点,
如果环上点个数为奇数,
那么添边后的收益
=2*(cnt[ cycle[half+1] - cycle[half+2] ])+4*(cnt[ cycle[half+2] - cycle[half+3] ])+6*(…)+2*(tot-half)*cnt[ cycle[tot] ];
没错,最后一个是cnt[ cycle[tot] ],不是cnt[ cycle[tot-1]-cycle[tot] ]。
如果环上点个数为偶数,
那么添边后的收益
=1*(cnt[ cycle[half+1] - cycle[half+2] ])+3*(cnt[half+2] - cnt[ cycle[half+3] ])+…+(2*(tot-half)-1)*cnt[tot]。
cnt数组可以由一次dfs得到,处理收益的过程可以由另一次dfs完成,因为计算收益的公式是有规律的,不同点的收益可以相互转化。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define PI acos(-1.0)
#define LL long long
#define ULL unsigned long long
#define LS (root<<1)
#define RS ((root<<1)|1)
#define LSON LS,l,mid
#define RSON RS,(mid+1),r
#define MID mid=((l+r)/2)
#define PR pair<int,int>
#define se second
#define MP make_pair
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
#define MOD 1000000007
#define idx(x) x-'a'
template<class T> T f_max(T a, T b){ return a > b ? a : b; }
template<class T> T f_min(T a, T b){ return a < b ? a : b; }
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> void f_swap(T &a, T &b){ T c; c = a; a = b; b = c; }
// 0x3f3f3f3f3f3f3f3f
// 0x3f3f3f3f
const int maxn=2e5+5;
vector<int> G[maxn];
int cnt[maxn], dep[maxn];
int path[maxn];
LL sum[maxn];
LL all;
LL f_ans=0;
void Init(int n){
for(int i=1;i<=n;i++)
G[i].clear();
all=0; f_ans=0;
}
void Dfs(int u,int fa,int depth){
cnt[u]=1; dep[u]=depth;
all+=dep[u];
for(int i=0, siz=G[u].size();i<siz;i++){
int v=G[u][i];
if(v==fa) continue;
Dfs(v, u, depth+1);
cnt[u]+=cnt[v];
}
}
void Dfs2(int u,int fa,int depth,LL ans){
path[depth]=u;
if(depth) sum[depth]=sum[depth-1]+cnt[fa]-cnt[u];
int half_depth=(depth+1)/2;
if(depth>1){
if(dep[u]%2==0){
int s=half_depth+1, t=depth;
ans-=1LL*2*(t-s)*cnt[u];
ans-=(sum[t]-sum[s]);
ans+=1LL*(2*(t-s)+1)*cnt[u];
}else{
int s=half_depth+1, t=depth;
ans-=1LL*(2*(t-s)+1)*cnt[u];
ans-=(sum[t]-sum[s-1]);
ans+=1L*2*(t-s+1)*cnt[u];
}
}
// printf("u=%d depth=%d ans=%d\n",u, depth, ans);
f_ans=max(f_ans, ans);
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(v==fa) continue;
Dfs2(v, u, depth+1, ans);
}
}
int main(){
int cas=0;
int T;
int n;
int u, v;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
Init(n);
for(int i=1;i<n;i++){
scanf("%d%d",&u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
Dfs(1,0,0);
sum[0]=0;
Dfs2(1,0,0,0);
printf("%lld\n",all-f_ans);
}
return 0;
}