Codeforces Round #798(Div 2)
作者:互联网
C
题意:给定一棵以 \(1\) 为根,\(n\) 个节点的二叉树,根节点被感染了。然后将会执行以下过程 \(n\) 次:
- 选定一个未被感染的节点,删除它,断开它周围的所有连边。
- 已感染的节点会沿其连边感染其相邻节点。
求最后最多可以有多少个节点未被感染(删除的节点不算)
分析:裸树形dp,\(dp[x]\) 表示 \(x\) 刚刚被感染,最多可以解救其子树内的多少个节点。
cpp
#include<bits/stdc++.h>
using namespace std;
#define f(i, a, b) for(int i = a; i <= b; i++)
#define mod9 998244353
#define mod1 1000000007
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define endl '\n'
int n;
vector<vector<int>> g;
vector<int> sz;
vector<int> dp;
void dfs1(int x, int fa){
int nowsz=1;
f(i, 0, (int)g[x].size()-1){
if(g[x][i] != fa) {
dfs1(g[x][i], x);
nowsz += sz[g[x][i]];
}
}
sz[x] = nowsz;
}
void dfs2(int x, int fa) {
if(g[x].size() == 1 && x != 1) return;
if((g[x].size() == 2&&x!=1) || (g[x].size()==1&&x==1)) {
f(i,0,(int)g[x].size()-1){
if(g[x][i]!=fa){
dfs2(g[x][i],x);
dp[x]=sz[g[x][i]]-1;
}
}
return;
}
if(g[x].size() == 3 || (g[x].size()==2&&x==1)) {
int lson=0,rson=0;
f(i,0,(int)g[x].size()-1){
if(g[x][i]!=fa){
if(!lson) lson=g[x][i]; else rson=g[x][i];
dfs2(g[x][i],x);
}
}
dp[x]=max(sz[lson]-1+dp[rson],sz[rson]-1+dp[lson]);
return;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(NULL);
cout.tie(NULL);
int t;cin>>t;
while(t--){
cin>>n;
g.clear(); g.resize(n + 10);
sz.clear(); sz.resize(n + 10);
dp.clear(); dp.resize(n + 10);
int ans = 0;
f(i,1,n-1){
int u, v; cin >> u >> v;
g[u].push_back(v); g[v].push_back(u);
}
dfs1(1, 0);
dfs2(1, 0);
cout << dp[1] << endl;
}
return 0;
}
启发:考试的时候想了一个奇怪的 \(dp\),遇到树还是想树形 \(dp\)(子节点上传到父节点)。
标签:sz,int,Codeforces,798,lson,Div,节点,dp,size 来源: https://www.cnblogs.com/Zeardoe/p/16365569.html