题意:
给一颗包含n个节点的树。每个节点上都有一个小写字母。现在给节点v和深度h,求节点v子树的深度为h的点上的字符能否组成回文。
链接:http://codeforces.com/contest/570/problem/D
我的做法:对所有点都重编号,使得同一层的点都是连续的(按层次重编号),然后记录每一层的26个字母出现的次数,对于每个查询u,h,找u下深度为h的左右端点,明显可知道如果字母出现次数为奇数的出现一次以上一定不能组成回文。。
tips:写完后发现根本不用树状数组啊。直接求前缀和就行。。。
tips2:这里有一个优化,只需要求异或和就行了,我们只在意奇偶并不在意具体数量。
tips3:这里还有一个优化,用一个int就可以存下了,因为只有26个字母。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <set> #include <vector> #include <map> #include <queue> #include <set> #include <algorithm> #include <limits> using namespace std; typedef long long LL; const int MAXN=500000+1000; const int INF = numeric_limits<int>::max(); const LL LL_INF= numeric_limits<LL>::max(); vector <int> dep[MAXN]; int n,m; int fa[MAXN][21]; int d[MAXN]; int clib(int a,int x){ int y=0; while(x){ if(x&1)a=fa[a][y]; x>>=1; ++y; } return a; } int C[MAXN]; int p[MAXN]; struct Edge { int to,next; Edge(){} Edge(int _to,int _next):to(_to),next(_next){} }e[MAXN]; int head[MAXN],tot; void init(){ memset(head,-1,sizeof(head)); tot=0; } void AddEdge(int u,int v){ e[tot]=Edge(v,head[u]); head[u]=tot++; } int id[MAXN],rid[MAXN]; int Tx[MAXN]; int que[MAXN],front,rear; int main() { while(~scanf("%d%d",&n,&m)){ for(int i=2,x;i<=n;i++){ scanf("%d",&x); p[i]=x; } init(); for(int i=n;i>=2;i--){ AddEdge(p[i],i); } id[0]=1; id[1]=1; rid[1]=1; dep[1].push_back(1); fa[1][0]=1; d[1]=1; int mm=0; front=rear=0; que[front++]=1; while(front!=rear){ int i=que[rear++]; for(int j=head[i];~j;j=e[j].next){ int v=e[j].to; id[v]=++id[0]; rid[id[0]]=v; d[id[v]]=d[id[i]]+1; mm=max(d[id[v]],mm); dep[d[id[v]]].push_back(id[v]); fa[id[v]][0]=id[i]; for(int k=1;k<=20;k++) fa[id[v]][k]=fa[fa[id[v]][k-1]][k-1]; que[front++]=v; } } memset(C,0,sizeof(C)); char ch; for(int i=1;i<=n;i++){ scanf(" %c",&ch); Tx[id[i]]=(1<<(ch-'a')); } for(int i=1;i<=n;i++){ C[i]=C[i-1]^Tx[i]; } int v,h; while(m--){ scanf("%d%d",&v,&h); v=id[v]; if(d[v]>=h){ puts("Yes"); continue; } if(dep[h].empty()){ puts("Yes"); continue; } int sz=dep[h].size(); int l=0,r=sz-1; int ansl=0,ansr=r;
while(l<=r){ int mid=(l+r)>>1; int u=clib(dep[h][mid],h-d[v]); if(u<v){ ansl=mid; l=mid+1; } else r=mid-1; } l=0,r=sz-1; while(l<=r){ int mid=(l+r)>>1; int u=clib(dep[h][mid],h-d[v]); if(u>v){ ansr=mid; r=mid-1; } else l=mid+1; } if(clib(dep[h][ansl],h-d[v])!=v){ ansl++; } if(clib(dep[h][ansr],h-d[v])!=v){ ansr--; } if(ansl>sz-1||ansr<0){ puts("Yes"); continue; } if(clib(dep[h][ansl],h-d[v])!=v){ puts("Yes"); continue; } ansl=dep[h][ansl]; ansr=dep[h][ansr]; int ji=0; int t=C[ansr]^C[ansl-1]; while(t>0){ ++ji; t-=t&-t; }
if(ji>1)puts("No"); else puts("Yes"); } } return 0; }
|