CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
阿新 • • 發佈:2020-09-08
Solution
因為要求路徑上的字元重新排序後為迴文串,也就是說出現次數為奇數的字元不會超過一個。我們給每個字元一個 \(2^x\) 形式的權值,那麼合法路徑異或和要麼為 \(0\) ,要麼為 \(2^x\) 的形式。
設點 \(x\) 到根的異或和為 \(D_x\) ,由於是邊權,x和y路徑上的異或和可以用 \(D_x~xor~D_y\) 來表示。再用一個數組 \(c\) 來儲存答案。其中 \(c_i\) 表示 \(D_x=i\) 的 \(x\) 的最大深度。
我們可以用 \(dsu~on~tree\) 來將複雜度優化到 \(O(n\log~n)\) ,因為 \(dsu~on~tree\)
程式碼
#include<cstring> #include<cstdio> #include<algorithm> #include<iostream> #include<cmath> using namespace std; const int N=500010,INF=1<<30; int n,c[1<<22],son[N],siz[N],dep[N]; int head[N],nxt[N],D[N],ans[N]; inline int read(){ int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();} return x*f; } void dfs(int u){ siz[u]=1; for(int i=head[u];i;i=nxt[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 init(int u){ c[D[u]]=-INF; for(int i=head[u];i;i=nxt[i]) init(i); } int o; void up(int u){ ans[o]=max(ans[o],dep[u]+c[D[u]]); for(int i=0;i<=21;i++) ans[o]=max(ans[o],dep[u]+c[1<<i^D[u]]); for(int i=head[u];i;i=nxt[i]) up(i); } void ins(int u){ c[D[u]]=max(c[D[u]],dep[u]); for(int i=head[u];i;i=nxt[i]) ins(i); } //dsu on tree void work(int u){ for(int i=head[u];i;i=nxt[i]) if(i!=son[u]) work(i),init(i); if(son[u]) work(son[u]); o=u; for(int i=head[u];i;i=nxt[i]) if(i!=son[u]) up(i),ins(i); c[D[u]]=max(c[D[u]],dep[u]); ans[u]=max(ans[u],dep[u]+c[D[u]]); for(int i=0;i<=21;i++) ans[u]=max(ans[u],dep[u]+c[1<<i^D[u]]);//列舉滿足條件的y ans[u]-=dep[u]<<1;//x-y的距離=dep[y]+dep[x]-2*dep[x] for(int i=head[u];i;i=nxt[i]) ans[u]=max(ans[u],ans[i]);//在子樹內比較 } int main(){ n=read(); for(int i=0;i<(1<<22);i++) c[i]=-INF; for(int i=2,x;i<=n;i++){ x=read(); nxt[i]=head[x];head[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; }