1. 程式人生 > >【CodeForces】914 E. Palindromes in a Tree 點分治

【CodeForces】914 E. Palindromes in a Tree 點分治

統計 bool truct oot print i++ rom tar edge

【題目】E. Palindromes in a Tree

【題意】給定一棵樹,每個點都有一個a~t的字符,一條路徑回文定義為路徑上的字符存在一個排列構成回文串,求經過每個點的回文路徑數。n<=2*10^5。

【算法】點分治

【題解】狀壓20位的二進制表示一條路徑的字符狀態,點分治過程中維護掃描過的路徑只須維護狀態桶數組,t[i]表示前面狀態為i的路徑條數。

合並:考慮當前狀態為j,要使合並的狀態滿足條件即i^j=1<<k(0<=k<20)或i^j=0,移項得i=j^(1<<k)或i=j,所以路徑數是Σ t [ j^(1<<k) ]+t[j]。

統計每個點:對於當前要處理的重心x,先遍歷所有子樹得到整個t[]數組,然後對每個子樹先刪除其在桶裏的狀態,然後掃一遍貢獻子樹中每個點,最後將子樹的狀態加回桶中。

這樣可以做到每條路徑都貢獻到每個點,要特殊處理重心的貢獻。

復雜度O(n log n)。

技術分享圖片
#include<cstdio>
#include<cctype>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=200010,maxN=2000010;
int tot,first[maxn],sz[maxn],vis[maxn],sum,root,a[maxn],u,v,n;
ll ans[maxn],t[maxN];
struct edge{int v,from;}e[maxn*2
]; void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;} void getroot(int x,int fa){ sz[x]=1; bool ok=1; for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa&&!vis[e[i].v]){ getroot(e[i].v,x); sz[x]+=sz[e[i].v]; if(sz[e[i].v]>sum/2)ok=0
; } if(ok&&sz[x]>=sum/2)root=x; } void dfs(int x,int fa,int p,int s){ t[s^=(1<<a[x])]+=p; for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa&&!vis[e[i].v])dfs(e[i].v,x,p,s); } ll calc(int x,int fa,int s){ s^=(1<<a[x]);ll num=t[s]; for(int i=0;i<20;i++)num+=t[s^(1<<i)]; for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa&&!vis[e[i].v])num+=calc(e[i].v,x,s); ans[x]+=num; return num; } void solve(int x,int s){ vis[x]=1; dfs(x,0,1,0); ll num=t[0]; for(int i=0;i<20;i++)num+=t[1<<i]; for(int i=first[x];i;i=e[i].from)if(!vis[e[i].v]){ dfs(e[i].v,x,-1,1<<a[x]); num+=calc(e[i].v,x,0); dfs(e[i].v,x,1,1<<a[x]); } ans[x]+=num/2; dfs(x,0,-1,0); for(int i=first[x];i;i=e[i].from)if(!vis[e[i].v]){ if(sz[e[i].v]>sz[x])sum=s-sz[x];else sum=sz[e[i].v]; getroot(e[i].v,x); solve(root,sum); } } char s[maxn]; int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); insert(u,v);insert(v,u); } scanf("%s",s+1); for(int i=1;i<=n;i++)a[i]=s[i]-a; sum=n; getroot(1,0); solve(root,sum); for(int i=1;i<=n;i++)printf("%lld ",ans[i]+1); return 0; }
View Code

【CodeForces】914 E. Palindromes in a Tree 點分治