【NOIP模拟】彩色树【树形dp】【树链剖分性质】【复杂度分析】
生活随笔
收集整理的這篇文章主要介紹了
【NOIP模拟】彩色树【树形dp】【树链剖分性质】【复杂度分析】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:一棵初始時為空的樹,依次加入 nnn 個葉結點,每次加入后詢問 用若干不同顏色的路徑將樹邊染色后 每個點到根經過的顏色數 的最大值 的最小值。
n≤106n\leq 10^6n≤106
首先發現這個路徑沒啥用,其實就是個剖分方案。
然后我考場以為是重鏈剖分,瞎胡了個東西上去獲得了 5 分的好成績。
把邊的顏色放在兒子上,根結點沒有顏色。這樣所求就是到根路徑上的所有點的顏色種類,根結點特判一下。
設 f(u)f(u)f(u) 表示 uuu 為根的答案,轉移時選擇除一個兒子外其他兒子 +1+1+1 再取 max?\maxmax ,顯然是取 fff 最大的,稱為重兒子。
由于存在一個叫重鏈剖分的東西,所以這個 f(u)f(u)f(u) 是 O(log?sizu)O(\log siz_u)O(logsizu?) 的。考慮暴力。
維護每個點的重兒子和 dp 值,插入一個葉子后暴力往上跳。如果是重兒子,直接讓父親取 max?\maxmax。如果不是,判下是否需要切換成重兒子,如果切換的話父親的 dp 值修改為原來的重兒子 +1+1+1。更新不了后立刻退出。
復雜度 O(nlog?n)O(n\log n)O(nlogn)。
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #define MAXN 1000005 using namespace std; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } int fa[MAXN],dp[MAXN],mx[MAXN]; int main() {freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);int n=read();puts("0");for (int u=2;u<=n;u++){fa[u]=read();dp[u]=1;for (int i=u;i>1;i=fa[i]) if (fa[i]==1) dp[1]=max(dp[1],dp[i]);elseif (i==mx[fa[i]]){if (dp[i]>dp[fa[i]]) ++dp[fa[i]];else break;}else{if (!mx[fa[i]]) mx[fa[i]]=i;else if (dp[i]==dp[fa[i]]) dp[fa[i]]=dp[mx[fa[i]]]+1,mx[fa[i]]=i;else break;}printf("%d\n",dp[1]);}return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的【NOIP模拟】彩色树【树形dp】【树链剖分性质】【复杂度分析】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【ROI 2019 Day2】课桌【贪心
- 下一篇: NOIP2020 赛前总结