CF1187E Tree Painting

这题用换根DP非常好处理。

先用\(1\)为根树形DP出第一个把\(1\)号点变成黑点所得到的贡献。然后发现若\(x\)的答案为\(a[x]\)\(v\)\(x\)的子节点,那么\(a[v]=a[x]+n-2 \times siz[v]\)(换根过程)。
然后对每个点的答案去一个最大值就好了。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long LL;
const int N=200009;
int n,head[N],cnt,siz[N];
LL fuck[N],ans,a[N];
struct Edge
{
	int nxt,to;
}g[N*2];

void add(int from,int to)
{
	g[++cnt].nxt=head[from];
	g[cnt].to=to;
	head[from]=cnt;
}

void init()
{
	scanf("%d",&n);
	int x,y;
	for (int i=1;i<n;i++)
		scanf("%d %d",&x,&y),add(x,y),add(y,x);
}

void dfs(int x,int fa)
{
	siz[x]=1;
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa)
			continue;
		dfs(v,x);
		siz[x]+=siz[v];
		fuck[x]+=fuck[v];
	}
	fuck[x]+=siz[x];
}

void DFS(int x,int fa)
{
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa)
			continue;
		a[v]=a[x]-siz[v]+n-siz[v];
		ans=max(ans,a[v]);
		DFS(v,x);
	}
}

void work()
{
	dfs(1,-1);
	ans=a[1]=fuck[1];
	DFS(1,-1);
	printf("%lld\n",ans);
}

int main()
{
	init();
	work();
	return 0;
}
posted @ 2020-04-20 08:16  With_penguin  阅读(74)  评论(0编辑  收藏  举报