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

MACE ATTACKKKKKKKKKKKKKKKKKKKK!!!!!!!!!!!!
浙公网安备 33010602011771号