題目連接:Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh pathsios
第一次寫\(dsu\ on\ tree\),來記錄一下數組
\(dsu\ on\ tree\)主要維護子樹信息,每每能夠省掉一個數據結構的啓發式合併。大致思路以下:數據結構
輕重鏈路徑剖分以後,對每一個點先遞歸處理他的全部輕兒子,每次處理完輕兒子以後把這棵子樹的信息清空。最後再來處理重孩子,重兒子的信息就能夠不用清空了。因爲咱們是用一個全局數組來記錄信息的,重兒子子樹的信息就仍然保留在全局數組中。接着咱們另外寫一個函數\(dfs\)全部的輕兒子子樹,並統計答案。每統計完一棵子樹的答案就能夠把這棵子樹的信息計入全局數組中,用於下一次更新。因爲每一個點到根的輕邊條數是\(\log n\)級別的,因此每一個點最多被掃\(\log n\)遍。函數
回到這道題上來。因爲要求路徑上的全部字符從新排列以後能夠造成一個迴文串,也就是說出現次數爲奇數的字符不會超過\(1\)個。那麼咱們就能夠給每一個字符一個\(2^x\)形式的權值,這樣的話合法路徑的異或和要麼爲\(0\),要麼爲\(2^x\)的形式。spa
設點\(x\)到根的異或和爲\(D_x\),因爲這道題是邊權,\(x\)和\(y\)路徑上的異或和就能夠用\(D_x\ xor\ D_y\)來表示。這樣的話就能夠用一個數組\(c\)來統計答案,其中\(c_i\)表示知足\(D_x=i\)的\(x\)的最大深度。剩下的就是套\(dsu\ on\ tree\)的板子了。code
下面貼代碼:blog
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define maxn 500010 #define INF (1<<30) using namespace std; typedef long long llg; int n,ci[1<<22],son[maxn],siz[maxn],dep[maxn]; int hd[maxn],nt[maxn],D[maxn],ans[maxn]; int getint(){ int w=0;bool q=0; char c=getchar(); while((c>'9'||c<'0')&&c!='-') c=getchar(); if(c=='-') c=getchar(),q=1; while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } void dfs(int u){ siz[u]=1; for(int i=hd[u];i;i=nt[i]){ D[i]^=D[u]; dep[i]=dep[u]+1; dfs(i); siz[u]+=siz[i]; if(siz[i]>siz[son[u]]) son[u]=i; } } void undo(int u){ ci[D[u]]=-INF; for(int i=hd[u];i;i=nt[i]) undo(i); } int o; void up(int &x,int y){if(y>x) x=y;} void up(int u){ up(ans[o],dep[u]+ci[D[u]]); for(int i=0;i<=21;i++) up(ans[o],dep[u]+ci[1<<i^D[u]]); for(int i=hd[u];i;i=nt[i]) up(i); } void ins(int u){ up(ci[D[u]],dep[u]); for(int i=hd[u];i;i=nt[i]) ins(i); } void work(int u){ for(int i=hd[u];i;i=nt[i]) if(i!=son[u]) work(i),undo(i); if(son[u]) work(son[u]); o=u; for(int i=hd[u];i;i=nt[i]) if(i!=son[u]) up(i),ins(i); up(ci[D[u]],dep[u]); up(ans[u],dep[u]+ci[D[u]]); for(int i=0;i<=21;i++) up(ans[u],dep[u]+ci[1<<i^D[u]]); ans[u]-=dep[u]<<1; for(int i=hd[u];i;i=nt[i]) up(ans[u],ans[i]); } int main(){ File("a"); n=getint(); for(int i=0;i<(1<<22);i++) ci[i]=-INF; for(int i=2,x;i<=n;i++){ x=getint(); nt[i]=hd[x];hd[x]=i; char c=getchar(); while(c>'v' || c<'a') c=getchar(); D[i]=1<<(c-'a'); } dfs(1); work(1); for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }