CF1646D题解
傳送門
首先我們可以發現,當 n≥2n \geq 2n≥2 的時候,任意兩個相鄰的點不可能同為好節點(((因為一定有其它節點破壞他們兩個相等)))。當 n=2n = 2n=2 的時候,特判掉即可。
我們考慮如何進行樹形 DPDPDP,設 f[u][1/0]f[u][1/0]f[u][1/0] 表示在以 uuu 為根的子樹中,uuu 是好節點 (f[u][1])(f[u][1])(f[u][1]) 或者不是好節點 (f[u][0])(f[u][0])(f[u][0]) 的時候,最多能有多少個好節點。在轉移的過程中 ,因為有上述的性質,所以當欽定 uuu 為好節點時,它的孩子 vvv 只能不是好節點,當 uuu 不是好節點時,它的孩子 vvv 可以是好節點,也可以不是好節點。
我們將 DPDPDP 的數組定義一個 pairpairpair,firstfirstfirst 表示好節點的數目,secondsecondsecond 表示在這個數目下所需要的和。轉移的時候分別對于 firstfirstfirst 和 secondsecondsecond 轉移,當 firstfirstfirst 相同的時候,要轉移 secondsecondsecond 小的。我們貪心的想,最后的方案一定是,所有不是好節點的值是 111,所有是好節點的值是 deg[u]deg[u]deg[u]。
具體轉移如下:
{f[u][1]=∑f[v][0]+1f[u][0]=max?(f[v][0],f[v][1])\begin{cases} f[u][1] = \sum{f[v][0]}+1\\ f[u][0] = \max(f[v][0],f[v][1]) \end{cases}{f[u][1]=∑f[v][0]+1f[u][0]=max(f[v][0],f[v][1])?
最后就是輸出方案了,先將根節點(((規定為1)1)1)是好節點還是不是好節點最優,然后往下 dfsdfsdfs,如果這個節點是好節點,那么孩子節點就都不能是好節點,一直把整棵樹遍歷完,最后輸出答案即可。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #define re register #define rep(a,b,c) for(re int a(b) ; a<=c ; ++a) #define drep(a,b,c) for(re int a(b) ; a>=c ; --a) using namespace std; inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}return x*f; } const int M = 4e5+10; typedef pair<int,int> pii; int n,cnt; int head[M],du[M],ans[M]; pii f[M][2]; struct edge{int to,nxt; }e[M]; inline void add(int u,int v){e[++cnt].to = v;e[cnt].nxt = head[u];head[u] = cnt; } inline bool check(pii x,pii y){if(x.first != y.first) return x.first > y.first;return x.second < y.second; } inline void dfs(int u,int fa){f[u][1] = make_pair(1,du[u]);f[u][0] = make_pair(0,1);for(re int i(head[u]) ; i ; i=e[i].nxt){int v = e[i].to;if(v == fa) continue;dfs(v,u);f[u][1].first += f[v][0].first;f[u][1].second += f[v][0].second;if(check(f[v][0],f[v][1])) f[u][0].first += f[v][0].first,f[u][0].second += f[v][0].second;else f[u][0].first += f[v][1].first,f[u][0].second += f[v][1].second;} } inline void print(int u,int fa,int zt){if(zt) ans[u] = du[u];else ans[u] = 1;for(re int i(head[u]) ; i ; i=e[i].nxt){int v = e[i].to;if(v == fa) continue;if(zt) print(v,u,0);else{if(check(f[v][0],f[v][1])) print(v,u,0);else print(v,u,1);}} } signed main(){n = read();rep(i,1,n-1){int u = read(),v = read();add(u,v),add(v,u);du[u]++,du[v]++;}if(n == 2){printf("2 2\n");printf("1 1\n");return 0;}dfs(1,0);if(check(f[1][0],f[1][1])){printf("%d %d\n",f[1][0].first,f[1][0].second);print(1,0,0);}else{printf("%d %d\n",f[1][1].first,f[1][1].second);print(1,0,1);}rep(i,1,n) printf("%d ",ans[i]);return 0; }總結
- 上一篇: springboot layuiAdmi
- 下一篇: 2023美赛基础知识以及如何入门