ZOJ - 3949(树形dp)

题解:我们先求出所有根到所有树上路径的总值,最后我们需要求的是加到哪条边上面的值后权值最小,假设根是第0层,u是第n层,求第i层会开始变少那么,数值应该是 n-i+1-i<0  =》 (n+1)/2 < i那么如果当n是奇数的话那么应该从(n+1)/2+1层开始他的子树的路径要都要减去2,4,6,8。。。2*m,,如果当n是偶数的话i应该从第(n+1)/2层开始他的子树路径减少1,3,5,7,9..2*m+1,

假设我们是从第i层开始减少的路径权值,那么当n是奇数的时候最后减少的路径值是2*son[i]-2*son[i+1]+4*son[i+1]-4*son[i+2]+6*son[i+2].....2*m*son[n] = 2*son[i]+...2*son[m](son[i]表示那一层被影响到的子树个数)就是路径的减少数目,如果n是偶数同理,因为i是会变动的那么我们可以用一颗树状数组维护一下前驱即可

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<cstdlib>
#include<ctime>
#include<stack>
using namespace std;
#define mes(a) memset(a,0,sizeof(a))
#define rep(i,a,b) for(i = a; i <= b; i++)
#define dec(i,a,b) for(i = b; i >= a; i--)
#define fi first
#define se second
#define ls rt<<1
#define rs rt<<1|1
#define mid (L+R)/2
#define lson ls,L,mid
#define rson rs,mid+1,R
#define lowbit(x) x&(-x)
typedef double db;
typedef long long int ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
const int mx = 2e5+5;
const int x_move[] = {1,-1,0,0,1,1,-1,-1};
const int y_move[] = {0,0,1,-1,1,-1,1,-1};
int n,m;
vector<int>g[mx];
ll dp[mx];
ll son[mx];
ll deep[mx];
ll sum[mx];
ll ans;
void init(){
	deep[0] = -1;
	for(int i = 1; i <= n; i++)
		g[i].clear();
	sum[n] = 0;
	for(int i = 1; i < n; i++){
		int u,v;
		scanf("%d%d",&u,&v);
		sum[i] = 0;
		g[u].push_back(v);
		g[v].push_back(u);
	}
}
void dfs(int u,int fa){
	deep[u] = deep[fa]+1;
	son[u] = 1;
	dp[u] = 0;
	for(auto v: g[u]){
		if(v!=fa){
			dfs(v,u);
			dp[u] += dp[v]+son[v];
			son[u] += son[v];
		}
	}
}
void add(int p,ll x){
	if(p==0)
		return;
	while(p<=n){
		sum[p] += x;
		p += lowbit(p);
	}
}
ll query(int p){
	ll ans = 0;
	while(p>0){
		ans += sum[p];
		p -= lowbit(p);
	}
	return ans;
}
void DFS(int u,int fa){
	add(deep[u],son[u]);
	if(deep[u]>=2){
		ll tmp = dp[1]-2*(query(deep[u])-query(deep[u]+1>>1));
		if(deep[u]%2==0)
			tmp += query((deep[u]+1>>1)+1)-query(deep[u]+1>>1);
		ans = min(ans,tmp);
	}
	for(auto v: g[u]){
		if(v!=fa)
			DFS(v,u);
	}
	add(deep[u],-son[u]);
}
int main(){
	int t,q,ca = 1;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		init();
		dfs(1,0);
		ans = dp[1];
		//for(int i = 2; i <= n; i++)
		//	ans = min(dp[1]-(deep[i]-1)*son[i],ans);
		DFS(1,0);
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/a1325136367/article/details/79719385