当前位置: 代码迷 >> 综合 >> Codecraft-18 and Codeforces Round #458 E. Palindromes in a Tree(点分治)
  详细解决方案

Codecraft-18 and Codeforces Round #458 E. Palindromes in a Tree(点分治)

热度:11   发布时间:2023-12-17 03:25:23.0

题意:

     一棵树,每个点都有一个字母,如果一条路径的字符的某个排列是回文串,就称这个路径是回文的,问经过每个点的回文路径有多少条

思路:

     很明显的点分治。首先因为字母是a到t,所以可以状压一下,利用异或来改变路径的状态,那么任意一个路径都可以用一个值来表示,如果一个值的二进制中1的个数小于等于1,那么这个路径就是回文的(利用__builtin_popcount函数)。
    然后根据树分治的思想,我们选取了一个重心,我们先把以重心为根,所有子树的所有路径通过状压后的值用一个数组记录数量。我们这里要做的,就是统计通过某个点的回文路径有多少条。当我们要算某个子树的贡献时,我们就先删去这个子树的所有的路径的值的贡献,然后统计答案,统计完了再把这些值放回去。
     但是存在一个问题,就是当我们发现dfs到某个点的时候,路径构成的值可以构成一个回文路径时,需要把重心到这个点的路径上的所有点的答案都加上一个值。这里可以通过dfs的时候顺便记录子树的贡献,记录完后把值返还给父亲即可。
     剩下的就是一些小细节了(其实细节还蛮多的),写的时候注意一下即可

错误及反思:

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 200100;struct EDGE{int to,next;
}e[N*2];
int first[N],n,tot,si[N],maxn[N],k;
long long ans[N];
bool did[N];
char s[N];
long long m[2000000];
vector<int> v;void addedge(int x,int y){e[tot].to=y;e[tot].next=first[x];first[x]=tot++;e[tot].to=x;e[tot].next=first[y];first[y]=tot++;
}void dfs_size(int now,int fa){si[now]=1;maxn[now]=0;for(int i=first[now];i!=-1;i=e[i].next)if(e[i].to!=fa&&!did[e[i].to]){dfs_size(e[i].to,now);si[now]+=si[e[i].to];maxn[now]=max(maxn[now],si[e[i].to]);}
}void dfs_root(int now,int fa,int& root,int& nu,int t){int MA=max(maxn[now],si[t]-si[now]);if(MA<nu){nu=MA;root=now;}for(int i=first[now];i!=-1;i=e[i].next)if(e[i].to!=fa&&!did[e[i].to])dfs_root(e[i].to,now,root,nu,t);
}void dfs2(int now,int fa,int tlen){for(int i=first[now];i!=-1;i=e[i].next)if(e[i].to!=fa&&!did[e[i].to])dfs2(e[i].to,now,tlen^(1<<(s[e[i].to]-'a')));v.push_back(tlen);
}long long dfs3(int now,int fa,int tlen,int root){long long num=0;for(int i=first[now];i!=-1;i=e[i].next)if(e[i].to!=fa&&!did[e[i].to]){num+=dfs3(e[i].to,now,tlen^(1<<(s[e[i].to]-'a')),root);}ans[now]+=num;for(int k=0;k<20;k++){num+=m[(1<<k)^tlen^(1<<(s[root]-'a'))];ans[now]+=m[(1<<k)^tlen^(1<<(s[root]-'a'))];}num+=m[tlen^(1<<(s[root]-'a'))];ans[now]+=m[tlen^(1<<(s[root]-'a'))];return num;
}long long dfs4(int now,int fa,int tlen,int root){long long num=0;for(int i=first[now];i!=-1;i=e[i].next)if(e[i].to!=fa&&!did[e[i].to]){num+=dfs4(e[i].to,now,tlen^(1<<(s[e[i].to]-'a')),root);}if(__builtin_popcount(tlen^(1<<(s[root]-'a')))<=1) num++;ans[now]+=num;return num;
}void solve(int now){int root,nu=1e9;dfs_size(now,-1);dfs_root(now,-1,root,nu,now);did[root]=true;for(int i=first[root];i!=-1;i=e[i].next){if(!did[e[i].to]){v.clear();dfs2(e[i].to,root,(1<<(s[e[i].to]-'a')));for(int j=0;j<v.size();j++) m[v[j]]++;}}long long td=0;for(int i=first[root];i!=-1;i=e[i].next){if(!did[e[i].to]){v.clear();dfs2(e[i].to,root,(1<<(s[e[i].to]-'a')));for(int j=0;j<v.size();j++) m[v[j]]--;td+=dfs3(e[i].to,root,(1<<(s[e[i].to]-'a')),root);ans[root]+=dfs4(e[i].to,root,(1<<(s[e[i].to]-'a')),root);for(int j=0;j<v.size();j++) m[v[j]]++;}}ans[root]+=td/2;for(int i=first[root];i!=-1;i=e[i].next){if(!did[e[i].to]){v.clear();dfs2(e[i].to,root,(1<<(s[e[i].to]-'a')));for(int j=0;j<v.size();j++) m[v[j]]--;}}for(int i=first[root];i!=-1;i=e[i].next)if(!did[e[i].to])solve(e[i].to);
}void init(){memset(first,-1,sizeof(first));tot=0;
}int main(){scanf("%d",&n);init();for(int i=0,u,v;i<n-1;i++){scanf("%d%d",&u,&v);addedge(u,v);}scanf("%s",s+1);solve(1);for(int i=1;i<=n;i++) printf("%lld ",ans[i]+1);
}
  相关解决方案