2/6换根dp总结

终极奥义:大运来咯!

前面忘了。做了一些换根dp的题。后面忘了。

力扣2581 统计可能的树根数目

第一遍 DFS:统计如果以1为根的形态下,有多少个猜测是正确的。
设cnt[i]为:以 i 为根时的正确猜测总数。

显然离线处理,使用set记录猜测。

然后在往下跑 DFS 时,查看一下 (u,v) 是否在 set 中。如果在,那么 \(cnt[1]\) 加 1。

第二遍 dfs:换根

转移失去的分数:

如果 Bob 猜过 [u, v] 得分 - 1

得到的分数:

如果 Bob 猜过 [v, u] 得分 + 1

换根公式:\(cnt[v]=cnt[u]-(u\rightarrow v猜过?)+(v\rightarrow u猜过?)\)

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int dp[100005];
vector<int> g[100005];
set<pair<int,int>> mp;
void dfs(int u,int Fa){
	for(auto i:g[u]){
		if(i==Fa)continue;
		dfs(i,u);
		dp[u]+=dp[i]+mp.count({u,i});
	}
}
void dfs2(int u,int Fa){
	for(auto i:g[u]){
		if(i==Fa) continue;
		dp[i]=dp[u]-mp.count({u,i})+mp.count({i,u});
		dfs2(i,u);
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	int n,T,k;
	cin>>n;
	for(int i=1,x,y;i<n;i++){
		cin>>x>>y;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	cin>>T;
	for(int i=1,x,y;i<=T;i++){
		cin>>x>>y;
		mp.insert({x,y});
	}
	dfs(0,inf);
	dfs2(0,inf);
	cin>>k;
	int ans=0;
	for(int i=0;i<n;i++) if(dp[i]>=k) ans++;
	cout<<ans;
	return 0;
}

CF1187E Tree Painting

万恶的推式子。

题目让我们通过选根最大化 \(\sum^{n}_{i=1}siz[i]\)。

显然是用换根大法。设 \(f[v]\) 为以 \(v\) 为根时的答案。显然:

\[f[u]=siz[u]+\sum_{v\in son(u)}siz[v] \]

第一遍dfs记录以1为根节点的答案。

第二遍dfs换根。

\(u\) 的答案表示为

\[\sum_{i\in son(u)\land i\neq v}f[i] \]

\(v\) 的答案表示为

\[\sum_{i\in son(v)}f[i] \]

那么答案有:

\[\begin{align*} ans[v] &= n + (n - siz[v]) + \sum_{i \in son_n, i \neq v} f[i] + \sum_{i \in son_v, i \neq v} f[i] \\ &= n + (n - siz[v]) + \sum_{i \in son_n, i \neq v} dp[i] + dp[v] - siz[v] \\ &= n + (n - siz[v]) + \sum_{i \in son_n} dp[i] - siz[v] \\ &= n + \sum_{i \in son_n} dp[i] + n - 2 \times siz[v] \\ &= g[u] + n - 2 \times siz[v] \end{align*} \]

然后可以直接写,也可以直接用 \(f[i]\) 记答案,省略 \(ans\)数组。

#include <bits/stdc++.h>
using namespace std;
int n;
vector<int> g[200005];
int siz[200005];
long long d1[200005],d2[200005];
void dfs1(int x, int fa){
	siz[x]=1;
	for(auto y:g[x]){
		if(y==fa) continue;
		dfs1(y,x);
		siz[x]+=siz[y];
		d1[x]+=d1[y];
	}
	d1[x]+=siz[x];
}
void dfs2(int x,int fa){
	for(auto y:g[x]){
		if(y==fa) continue;
		d2[y]=n-siz[y]+d2[x]-siz[y];
		dfs2(y,x);
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		int x,y;
		cin>>x>>y;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs1(1,0); d2[1]=d1[1];
	dfs2(1,0);
	long long ans=0;
	for(int i=1;i<=n;i++) ans=max(ans,d2[i]);
	cout<<ans;
	return 0;
}

P3478 [POI 2008] STA-Station

和CF1187E Tree Painting差不多,还简单一点。

#include<bits/stdc++.h>
using namespace std;
vector<int> g[1000005];
int n,cnt,id;
long long ans;
long long f[1000005],dep[1000005],siz[1000005];
void dfs1(int x,int fa){
	siz[x]=1;
	dep[x]=dep[fa]+1;
	for(auto y:g[x]){
		if(y==fa) continue;
		dfs1(y,x);
		siz[x]+=siz[y];
	}
}
void dfs2(int x,int fa){
	for(auto y:g[x]){
		if(y==fa) continue;
		f[y]=f[x]+n-2*siz[y];
		dfs2(y,x);
	}
}
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int x,y;
		cin>>x>>y;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs1(1,0);
	for(int i=1;i<=n;i++) f[1]+=dep[i];
	dfs2(1,0);
	for(int i=1;i<=n;i++) if(ans<f[i]) ans=f[i],id=i;
	cout<<id;
	return 0;
}

希望明天考试顺利qwq

posted @ 2026-02-06 19:04  vivid/stasis  阅读(41)  评论(0)    收藏  举报