CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)

一棵根为1 的树,每条边上有一个字符(a-v共22种)。 一条简单路径被称为Dokhtar-kosh当且仅当路径上的字符经过重新排序后可以变成一个回文串。 求每个子树中最长的Dokhtar-kosh路径的长度。

 

如果重排后能构成回文串,那么出现奇数次的字符最多一个。用一个22位二进制数表示每一个字母出现的次数的奇偶,把一个点到根节点的路径的异或值记为$s[u]$,那么就是在子树里找到两个点使其$s$值异或之后1的个数不超过1个,那么用dsu on tree就可以了

记得最后别忘了用儿子的答案更新自己的

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #define inf -0x3f3f3f3f
 6 using namespace std;
 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 8 char buf[1<<21],*p1=buf,*p2=buf;
 9 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
10 int read(){
11     #define num ch-'0'
12     char ch;bool flag=0;int res;
13     while(!isdigit(ch=getc()))
14     (ch=='-')&&(flag=true);
15     for(res=num;isdigit(ch=getc());res=res*10+num);
16     (flag)&&(res=-res);
17     #undef num
18     return res;
19 }
20 inline char getch(){
21     char ch;while((ch=getc())>'z'||ch<'a');return ch;
22 }
23 char sr[1<<21],z[20];int C=-1,Z;
24 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
25 void print(int x){
26     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
27     while(z[++Z]=x%10+48,x/=10);
28     while(sr[++C]=z[Z],--Z);sr[++C]=' ';
29 }
30 const int N=5e5+5;
31 int head[N],Next[N<<1],ver[N<<1],tot;
32 inline void add(int u,int v){
33     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
34 }
35 int sz[N],d[N],son[N],s[N],ans[N],f[N*20],a[N];char c[N];
36 int mx,n,bin[30];
37 void dfs1(int u,int fa){
38     sz[u]=1,d[u]=d[fa]+1,s[u]=s[fa]^bin[a[u]];
39     for(int i=head[u];i;i=Next[i]){
40         int v=ver[i];dfs1(v,u);
41         sz[u]+=sz[v];
42         if(sz[son[u]]<sz[v]) son[u]=v;
43     }
44 }
45 void calc(int rt,int u){
46     int now=s[u];cmax(mx,f[now]+d[u]-2*d[rt]);
47     if((s[u]^s[rt])==0) cmax(mx,d[u]-d[rt]);
48     for(int i=0;i<22;++i){
49         now=bin[i]^s[u];
50         cmax(mx,f[now]+d[u]-2*d[rt]);
51         if((s[u]^s[rt])==bin[i]) cmax(mx,d[u]-d[rt]);
52     }
53     for(int i=head[u];i;i=Next[i]) calc(rt,ver[i]);
54 }
55 void update(int u,int k){
56     k?cmax(f[s[u]],d[u]):f[s[u]]=inf;
57     for(int i=head[u];i;i=Next[i]) update(ver[i],k);
58 }
59 void dfs2(int u,int k){
60     for(int i=head[u];i;i=Next[i])
61     if(ver[i]!=son[u]) dfs2(ver[i],0);
62     if(son[u]) dfs2(son[u],1);
63     mx=0;int now=s[u];
64     cmax(mx,f[now]-d[u]);
65     for(int i=0;i<22;++i)
66     now=bin[i]^s[u],cmax(mx,f[now]-d[u]);
67     for(int i=head[u];i;i=Next[i])
68     if(ver[i]!=son[u]) calc(u,ver[i]),update(ver[i],1);
69     ans[u]=mx;
70     if(!k){
71         for(int i=head[u];i;i=Next[i]) update(ver[i],0);
72         f[s[u]]=inf;
73     }else cmax(f[s[u]],d[u]);
74 }
75 void spread(int u){
76     for(int i=head[u];i;i=Next[i]){
77         int v=ver[i];spread(v);
78         cmax(ans[u],ans[v]);
79     }
80 }
81 int main(){
82 //    freopen("testdata.in","r",stdin);
83     n=read();
84     bin[0]=1;for(int i=1;i<=25;++i) bin[i]=bin[i-1]<<1;
85     for(int i=2;i<=n;++i){
86         int u=read();c[i]=getch();
87         add(u,i),a[i]=c[i]-'a';
88     }
89     dfs1(1,0);
90     memset(f,0xef,sizeof(f));
91     dfs2(1,0);spread(1);
92     for(int i=1;i<=n;++i) print(ans[i]);
93     return Ot(),0;
94 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9817996.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值