CF741D [过长的题目名字] dsu on tree

传送门

因为题目名字太长会触发博客标题的神奇BUG所以就省略了题目名字/cy


以前一直在胡dsu on tree但是从来没写过,这次还是写写比较好。

我们维护一个数组\(f_S\)表示子树的所有路径中出现次数为奇数的路径集合为\(S\)时最大的长度,每当增加一条路径\(T\)的时候,当\(popcount(S \bigoplus T) \leq 1\)的时候可以贡献答案,这样的\(S\)最多只有\(\sigma + 1\)个,所以可以暴力枚举。

所以我们只需要快速合并子树信息并计算子树答案。考虑dsu on tree。

按照dsu on tree的惯常策略,解决当前点的时候先将其轻儿子解决掉然后清空掉\(f\)数组,最后解决重儿子。注意到将重儿子的数组上传还需要加上一条边产生的字符的影响,并且数组中所有元素的值均\(+1\)。我们可以使用两个标记,一个表示下标异或、一个表示全局加法标记,就可以解决这个问题。

当然打标记就意味着在统计的过程中有一些细节需要注意。

#include
using namespace std;

const int _ = 5e5 + 7;
#define PII pair < int , int >
#define st first
#define nd second
vector < PII > ch[_]; int mx[1 << 22] , id[_] , ans[_] , sz[_] , son[_] , mrk1[_] , mrk2[_] , N;

void dfs1(int x){sz[x] = 1; for(auto t : ch[x]){dfs1(t.st); sz[x] += sz[t.st]; if(sz[son[x]] < sz[t.st]) son[x] = t.st;}}

void clr(int x , int v){mx[v] = -1e9; for(auto t : ch[x]) clr(t.st , v ^ t.nd);}

void add(int x , int v , int l){mx[v] = max(mx[v] , l); for(auto t : ch[x]) add(t.st , v ^ t.nd , l + 1);}

void dsu(int x , int v , int l , int &ans){
    ans = max(ans , mx[v] + l); for(int i = 0 ; i < 22 ; ++i) ans = max(ans , mx[v ^ (1 << i)] + l);
    for(auto t : ch[x]) dsu(t.st , v ^ t.nd , l + 1 , ans);
}

void dfs(int x){
    if(son[x]){
        for(auto t : ch[x]) if(t.st != son[x]){dfs(t.st); clr(t.st , mrk1[t.st]);} else mrk1[x] ^= t.nd;
        dfs(son[x]); mrk1[x] ^= mrk1[son[x]]; mrk2[x] = mrk2[son[x]] + 1;
        ans[x] = max(ans[x] , max(mx[mrk1[x]] + mrk2[x] , ans[son[x]]));
        for(int i = 0 ; i < 22 ; ++i) ans[x] = max(ans[x] , mrk2[x] + mx[mrk1[x] ^ (1 << i)]);
        mx[mrk1[x]] = max(mx[mrk1[x]] , -mrk2[x]);
        for(auto t : ch[x])
            if(t.st != son[x]){
                dsu(t.st , t.nd ^ mrk1[x] , 1 + mrk2[x] , ans[x] = max(ans[x] , ans[t.st]));
                add(t.st , t.nd ^ mrk1[x] , 1 - mrk2[x]);
            }
    }
    else mx[0] = 0;
}

int main(){
    ios::sync_with_stdio(0); cin >> N; memset(mx , -0x3f , sizeof(mx));
    for(int i = 2 ; i <= N ; ++i){int fa; char s; cin >> fa >> s; ch[fa].push_back(PII(i , 1 << (s - 'a')));}
    dfs1(1); dfs(1); for(int i = 1 ; i <= N ; ++i) printf("%d " , ans[i]);
    return 0;
}

你可能感兴趣的:(CF741D [过长的题目名字] dsu on tree)