日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CF1646D题解

發布時間:2023/12/29 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CF1646D题解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門


首先我們可以發現,當 n≥2n \geq 2n2 的時候,任意兩個相鄰的點不可能同為好節點(((因為一定有其它節點破壞他們兩個相等)))。當 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 的數組定義一個 pairpairpairfirstfirstfirst 表示好節點的數目,secondsecondsecond 表示在這個數目下所需要的和。轉移的時候分別對于 firstfirstfirstsecondsecondsecond 轉移,當 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; }

總結

以上是生活随笔為你收集整理的CF1646D题解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。