codeforce E. Tree Painting(樹形dp||換根dp)

https://codeforces.com/contest/1187/problem/E

題意:給出一棵樹,一開始每個節點都爲白點,每次可以選擇一個點變爲黑點,獲得分數等於該白點所有相連白點的數量,問能得到的最大分數爲多少

思路:此題爲經點的樹形換根dp。
換根dp大體思路:
1.首先固定一個節點(一般取根節點)
2.考慮以該節點計算答案需要知道哪些條件(一般爲子樹的信息)
3.將根節點傳遞給子樹,本節點以及子節點需要更改的信息
4.子節點交換完畢,將該點信息以改變相反順序還原

考慮這道題:
1.首先固定0節點,以0節點獲得的最優答案顯然是依次選擇每個相鄰節點直到葉子節點
2.思考需要的條件:以每個子節點爲根的所有子樹的節點和+本身子節點數目,(每次選擇一個點需要計算本身節點的和及子節點子樹和),所以在第一次dfs處理處每個子節點數目num,以及子節點爲根的子樹節點和sum,那麼0節點的答案就是num[0]
3.考慮換根 x->to 斷開x-to連接 ,將to作爲新的根節點,對應num,sum變化(具體解釋看代碼)
4.該子節點換根完畢,恢復num,sum

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
using namespace std;

typedef long long ll;
typedef pair<char, ll> P;
typedef pair<P, int> LP;
const int inf = 0x3f3f3f3f;
const int N = 1e6 + 100;
const int mod = 1e9+7;
const int base=131;
tr1::unordered_map<ll,ll> mp;
inline ll mul(ll x,ll y) { return (x*y-(ll)((long double)x*y/mod)*mod+mod)%mod;}
inline ll ksm(ll a,ll b) {ll ans=1;while(b){if(b&1)ans=mul(ans,a);a=mul(a,a),b>>=1;}return ans;}


ll n,m;
ll num[N],vis[N],a[N],sum[N];
ll k,ans,cnt,res,x,y;
vector<int> v[N];

void dfs(int x,int fa)
{
	num[x]=1;
	for(int to:v[x])
	{
		if(to==fa) continue;
		dfs(to,x);
		sum[x]+=sum[to];//所有子節點爲根的子樹大小的和
		num[x]+=num[to];//處理每個節點子樹大小
	}
	sum[x]+=num[x];
}
void go(int x,int fa)
{
	ans=max(ans,sum[x]);
	for(int to:v[x])
	{
		if(to==fa) continue;

		sum[x]-=sum[to];//新樹以to作爲根,那麼x減去to作爲子節點的數目
		sum[x]-=num[to];// 這裏原本sun[x]=sum[to]+num[x] 所以要減去這兩個
		num[x]-=num[to];//減去該子節點子樹大小
		sum[to]+=sum[x];//to作爲根+x的子樹和
		sum[to]+=num[x];//同理加上子樹大小
		num[to]+=num[x];//加上x作爲子樹的大小


		go(to,x);//遍歷子節點

		num[to]-=num[x];
		sum[to]-=num[x];
		sum[to]-=sum[x];
		num[x]+=num[to];
		sum[x]+=num[to];
		sum[x]+=sum[to];
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	cin>>n;
	for(int i=1;i<n;i++)
	{
		cin>>x>>y;
		v[x].push_back(y);
		v[y].push_back(x);
	}
	dfs(1,-1);
	go(1,-1);
	cout<<ans<<endl;


}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章