【换根DP】CF1187E Tree Painting

Problem - 1187E - Codeforces

题意:

思路:

有限制的最值问题,很自然地想到换根DP

在考虑换根DP的时候,先把以1为根的答案求出来,即先把fi求出来,这个时候就用普通的树形DP求,dp数组对应的主体是子树,在状态转移的时候考虑的主体也是子树,在定义的时候记得把贡献说清楚,因为根据树形DP都是算贡献题,只有弄清楚要算的是什么贡献,才能正确地转移

所以树形DP在状态转移的时候需要考虑一下一般算贡献是怎么算的

然后在考虑换根的时候,因为以1作为根的答案f已经算出来了,换根之后,根据刚刚的转移方式,看看v的父节点u部分的去掉v的子树的新子树能不能用u的儿子和其他参数表示

即在上图中结点 j 的贡献能不能用 j 子树除去 i 子树的部分(用已经算出来的f数组表示)和i部分的子树(不能用f数组表示,因为fi表示的子树包括了i现在的父亲),当然有时候可以用容斥,大部分情况是用其他参数表示(参考f数组的转移方式)

Code:

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int mxn=3e5+10;
const int mxe=3e5+10;
const int Inf=1e18;

struct ty{
    int to,next;
}edge[mxe<<2];

int N,u,v,tot=0;
int head[mxn],sz[mxn],g[mxn],f[mxn];

void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void G_init(){
    tot=0;
    for(int i=0;i<=N;i++){
        head[i]=-1;
    }
}
void dfs1(int u,int fa){
	sz[u]=1;
	for(int i=head[u];~i;i=edge[i].next){
		if(edge[i].to==fa) continue;
		dfs1(edge[i].to,u);
		sz[u]+=sz[edge[i].to];
		g[u]+=g[edge[i].to];
	}
	g[u]+=sz[u];
}
void dfs2(int u,int fa){
	for(int i=head[u];~i;i=edge[i].next){
		if(edge[i].to==fa) continue;
		f[edge[i].to]=N+f[u]-2*sz[edge[i].to];
		dfs2(edge[i].to,u);
	}
}
void solve(){
	cin>>N;
	G_init();
	for(int i=1;i<=N-1;i++){
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	dfs1(1,0);
	f[1]=g[1];
	dfs2(1,0);
	int ans=0;
	for(int i=1;i<=N;i++){
		ans=max(ans,f[i]);
	}
	cout<<ans<<'\n';
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int __=1;//cin>>__;
    while(__--)solve();return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值