题意:
一棵树,每个节点是一个字母
跟节点深度为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;
}

京公网安备 11010502036488号