题意:
一棵树,每个节点是一个字母
跟节点深度为1
问对于x的子树,深度为y的节点能否组成回文串?
题解:
这个题处处都是细节
组成回文串的话,要求至多只有一个字母出现奇数次
我们先用dfs序给树标上号,同时开vector按照顺序存下每一层的节点以及每一层in[x]
对于每一层,我们已经知道有什么节点,然后把每一层节点对应的字母存起来,这个可以用二级制来存储,对于当前一层,该层内所有字母异或起来,然后用一个vector存储,相当于存了一个前缀和,反映了前x个字母的存在情况,0为该字母不存在或为偶数,1为出现次数为奇数
对于查询的x层,深度为y的情况
先通过二分查询到in[x]和out[y]的位置,分别是l和r
如果没有查询到out[y],说明该节点没有子树,那也算回文串
然后通过w=b[deep][r]^b[deep][l-1]可以得到区间[l,r]内所以字母的存在情况
w-=(w&(-w));相当于减去一个奇数的情况,如果还有奇数就输出no,否则就是yes
代码:
#include<bits/stdc++.h> typedef long long ll; using namespace std; inline int read(){ int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48); return s*w; } const int maxn=5e5+9; vector<int>edge[maxn]; int in[maxn],out[maxn]; int pos[maxn]; int cnt=0; int deep[maxn]; vector<int>poss[maxn],inn[maxn]; int maxdeep; vector<int>b[maxn]; void dfs(int u,int fa) { deep[u]=deep[fa]+1; maxdeep=max(maxdeep,deep[u]); in[u]=++cnt; pos[cnt]=u; poss[deep[u]].push_back(u);//存这一层的点 inn[deep[u]].push_back(in[u]);//存这一层的dfs序 for(int i=0;i<edge[u].size();i++) { int v=edge[u][i]; if(v==fa)continue; dfs(v,u); } out[u]=cnt; } int main() { ios::sync_with_stdio(false); int m,n; cin>>n>>m; for(int i=2;i<=n;i++) { int x; cin>>x; edge[x].push_back(i); } dfs(1,0); string s; cin>>s; for(int i=1;i<=maxdeep;i++) { int y=0; for(int j=0;j<poss[i].size();j++)//第i层的所有点 { int x=s[poss[i][j]-1]-'a'; y^=(1<<x); b[i].push_back(y); } } for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; int l,r; l=lower_bound(inn[y].begin(),inn[y].end(),in[x])-inn[y].begin();//大于等于in[x] r=upper_bound(inn[y].begin(),inn[y].end(),out[x])-inn[y].begin()-1;//大于in[x] if(r<0)//说明x没有子树 { printf("Yes\n"); // cout<<"Yes"<<endl; continue; } int w; if(l<1)w=b[y][r]; else if(l>0)w=b[y][l-1]^b[y][r]; w-=(w&(-w)); if(w==0)printf("Yes\n"); //cout<<"Yes"<<endl; else printf("No\n"); //cout<<"No"; } return 0; }