Codeforces Round #316 (Div. 2) D
题意:给你一个一棵树,树上的每个节点上有一个字符,询问 v,deep, 问深度为deep的,并且属于v子树的所有字符能不能组成一个回文,是数Yes,否则No
对于这颗树,我们可以用 时间戳 来表示点v所包含的区间
然后对于每一层我们可以把这些字符存在一个数组里面
所以要找到 属于V的字符,且在deep层
我们可以对于这一层进行二分(因为在同义层的时间时递增的)
#include<bits/stdc++.h> using namespace std; const int mmax = 5e5+10; int n,m; int depp[mmax],TT; char p[mmax]; struct Node{ int num[26]; }; vector<char>sum[mmax]; vector<int>ID[mmax]; vector<Node>ans[mmax]; vector<int>tp[mmax]; bool vit[mmax]; struct node{ int st,ed; }pp[mmax]; void dfs(int x,int cnt){ sum[cnt].push_back(p[x]); ID[cnt].push_back(x); TT++;vit[x]=1; pp[x].st=TT; for(int i=0;i<tp[x].size();i++){ int to=tp[x][i]; if(!vit[to]) dfs(to,cnt+1); } pp[x].ed=TT; } void init(){ for(int i=0;i<=n;i++) { sum[i].clear(); tp[i].clear(); ID[i].clear(); ans[i].clear(); } memset(ans,0,sizeof(ans)); memset(vit,0,sizeof(vit)); } int lfind(int l,int r,int x,int b){ int mid,ans=mmax; while(l<=r){ mid=(l+r)>>1; int id=ID[b][mid]; if(pp[id].st>=pp[x].st){ ans=mid;r=mid-1; } else l=mid+1; } return ans; } int rfind(int l,int r,int x,int b){ int mid,ans=-1; while(l<=r){ mid=(l+r)>>1; int id=ID[b][mid]; if(pp[id].ed<=pp[x].ed){ ans=mid;l=mid+1; } else r=mid-1; } return ans; } int main(){ #ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); #endif // ONLINE_JUDGE while(cin>>n>>m){ init(); for(int i=2;i<=n;i++){ int a;scanf("%d",&a); tp[a].push_back(i); tp[i].push_back(a); } TT=0; scanf("%s",p+1); dfs(1,1); for(int i=1;i<=n;i++){ if(sum[i].size()==0) continue; Node a; memset(a.num,0,sizeof(a.num)); for(int j=0;j<sum[i].size();j++){ int id=sum[i][j]-'a'; a.num[id]++; ans[i].push_back(a); } } for(int i=0;i<m;i++){ int a,b;scanf("%d%d",&a,&b); int ll,rr; ll=lfind(0,ans[b].size()-1,a,b); rr=rfind(0,ans[b].size()-1,a,b); if(ll>rr) puts("Yes"); else{ int tsum=0; if(ll==0){ tsum=0; for(int j=0;j<26;j++) if(ans[b][rr].num[j]&1) tsum++; } else{ Node a; for(int j=0;j<26;j++) a.num[j]=ans[b][rr].num[j]-ans[b][ll-1].num[j]; tsum=0; for(int j=0;j<26;j++) if(a.num[j]&1) tsum++; } if(tsum>1) puts("No"); else puts("Yes"); } } } }