1. 程式人生 > 實用技巧 >CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

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;
}