#樹鏈剖分,樹上啟發式合併#CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
阿新 • • 發佈:2020-08-19
分析
考慮迴文串當且僅當最多有一個字母出現奇數次,
可以記錄某個二進位制狀態的最大深度,
一種就是點\(x\)到某個點,另一種就是經過點\(x\)的一條路徑
在\(x\)的子樹中遞迴實現,重兒子保留,輕兒子將標記清空,
這樣時間複雜度可以做到\(O(nlog^2n)\)
程式碼
#include <cstdio> #include <cctype> #define rr register using namespace std; const int N=500011; struct node{int y,w,next;}e[N]; int k=1,son[N],ans[N],as[N],c[4200011],tt; int now,dep[N],fat[N],big[N],dis[N],n; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isalnum(c)) c=getchar(); while (isalnum(c)) ans=ans*10+c-48,c=getchar(); return ans; } inline void print(int ans){ if (ans>9) print(ans/10); putchar(ans%10+48); } inline signed max(int a,int b){return a>b?a:b;} inline void add(int x,int y,int w){e[++k]=(node){y,w,as[x]},as[x]=k;} inline void dfs1(int x,int fa){ dep[x]=dep[fa]+1,fat[x]=fa,son[x]=1; for (rr int i=as[x],mson=-1;i;i=e[i].next) if (e[i].y!=fa){ dis[e[i].y]=dis[x]^(1<<e[i].w); dfs1(e[i].y,x),son[x]+=son[e[i].y]; if (son[e[i].y]>mson) big[x]=e[i].y,mson=son[e[i].y]; } } inline void calc(int x){ if (c[dis[x]]) now=max(now,dep[x]+c[dis[x]]-tt); for (rr int i=0;i<22;++i) if (c[dis[x]^(1<<i)]) now=max(now,dep[x]+c[dis[x]^(1<<i)]-tt); } inline void update(int x,int z){ if (z==1) c[dis[x]]=max(c[dis[x]],dep[x]); else if (!z) calc(x); else c[dis[x]]=0; for (rr int i=as[x];i;i=e[i].next) if (e[i].y!=fat[x]) update(e[i].y,z); } inline void dfs2(int x,int opt){ for (rr int i=as[x];i;i=e[i].next) if (e[i].y!=fat[x]&&e[i].y!=big[x]) dfs2(e[i].y,0); if (big[x]) dfs2(big[x],1); tt=dep[x]<<1; for (rr int i=as[x];i;i=e[i].next) now=max(now,ans[e[i].y]); for (rr int i=as[x];i;i=e[i].next) if (e[i].y!=big[x]) update(e[i].y,0),update(e[i].y,1);//統計答案並新增深度 calc(x),c[dis[x]]=max(c[dis[x]],dep[x]),ans[x]=now;//更新該點 if (!opt) update(x,-1),now=0;//如果是輕兒子撤銷標記 } signed main(){ n=iut(); for (rr int i=2;i<=n;++i){ rr int x=iut(),w=iut()-49; add(x,i,w); } dfs1(1,0),dfs2(1,1); for (rr int i=1;i<=n;++i) print(ans[i]),putchar(32); return 0; }