1. 程式人生 > >Codeforces 741D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

Codeforces 741D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

mat code stdin mes name 啟發式合並 我們 pre const

Description

\(1\) 為根 的 \(n\) 個節點的樹,每條邊有一個顏色 \(x\),求每一個點的子樹內的好的路徑的最長長度
一條路徑被定義為好的當且僅當把所有經過的邊的字母經過排列之後可以變成回文
題面

Solution

理解了一下 \(dsu\,on\,tree\),相比普通的啟發式,省去了高級的數據結構,並省下了大量空間

好的路徑實際上就是出現奇數次的字母不多於一個,字符集只有 \(22\),可以狀壓起來
對於一條路徑的異或和實際上可以看成 \(dis[x]\)^\(dis[y]\)^\(a[lca]\),\(dis[x]\) 為點 \(x\) 到根的路徑的異或和
那麽普通的啟發式合並做法就是開一個 \(vector\)

\(map\),分別記錄每一狀態下的最長鏈
然後從小到大合並所有的子樹即可

考慮 \(dsu\,on\,tree\) 做法:
先按樹鏈剖分的做法劃分輕重鏈
然後大致思路就是:對於每一個輕兒子我們暴力合並,重兒子保留信息
為了節省空間,我們不能對每一個節點都開數組,所以開一個全局數組來維護這個東西
既然開的是全局變量,就要避免對其他子樹的影響,當然就有清空操作,對於輕兒子我們暴力遍歷其子樹把信息刪除
而一棵子樹內只有一個重鏈,所以重鏈之間沒有影響,可以不刪除,直接保留信息
然後暴力把輕兒子子樹內的信息合並,並更新答案就可以了

這樣做復雜度是 \(O(n*logn)\) 的,因為一個點到根路徑上的輕邊只有 \(log\)

條,所以均攤復雜度是 \(O(n*log)\)

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,head[N],nxt[N],num=0,to[N],c[N],sz[N],son[N];
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
int ans[N],dep[N],f[1<<22],o;
inline void dfs(int x){
    sz[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        dep[u]=dep[x]+1;c[u]^=c[x];dfs(u);sz[x]+=sz[u];
        if(sz[u]>sz[son[x]])son[x]=u;
    }
}
inline void Delet(int x){
    f[c[x]]=-N;
    for(int i=head[x];i;i=nxt[i])Delet(to[i]);
}
inline void Modify(int x){
    ans[o]=max(ans[o],f[c[x]]+dep[x]);
    for(int i=0;i<22;i++)ans[o]=max(ans[o],f[c[x]^(1<<i)]+dep[x]);
    for(int i=head[x];i;i=nxt[i])Modify(to[i]);
}
inline void ins(int x){
    f[c[x]]=max(f[c[x]],dep[x]);
    for(int i=head[x];i;i=nxt[i])ins(to[i]);
}
inline void dfs1(int x){
    for(int i=head[x];i;i=nxt[i])
        if(to[i]!=son[x])dfs1(to[i]),Delet(to[i]);
    if(son[x])dfs1(son[x]);o=x;
    for(int i=head[x];i;i=nxt[i])
        if(to[i]!=son[x])Modify(to[i]),ins(to[i]);
    f[c[x]]=max(f[c[x]],dep[x]);
    ans[o]=max(ans[o],f[c[x]]+dep[x]);
    for(int i=0;i<22;i++)ans[o]=max(ans[o],f[c[x]^(1<<i)]+dep[x]);
    ans[o]-=dep[x]<<1;
    for(int i=head[x];i;i=nxt[i])ans[x]=max(ans[x],ans[to[i]]);
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  scanf("%d",&n);
  char ch[2];int x;
  for(int i=(1<<22)-1;i>=0;i--)f[i]=-N;
  for(int i=2;i<=n;i++){
      scanf("%d%s",&x,ch);
      link(x,i);
      c[i]=1<<(ch[0]-'a');
  }
  dfs(1);dfs1(1);
  for(int i=1;i<=n;i++)printf("%d ",ans[i]);
  return 0;
}

Codeforces 741D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths