题意
给定一棵树,树上每个节点上有一个小写字符,给出一些询问,询问包括节点和深度,求出以这个节点为固定深度的节点上能否组成一个回文串。
题解
子树静态的问题,所以考虑树上启发合并,其实就是如何维护答案。
首先考虑回文串出现的条件,组成回文串的所有字母中奇数个的字母不超过1个。
由于总的字母类别不超过26个,我们可以利用二进制的思想,即每一个字母对应二进制的一位,若一个字母出现奇数次,那么该位为1,反之为0.
如果加入一个字母,则将当前的状态与字母对应的二进制位做异或即可,最后统计1的个数。这里可以使用位运算或者bitset
维护。
下面考虑如何统计答案,首先要有记录深度,
cnt[x]
c
n
t
[
x
]
表示深度为x当前子树的状态。如果要加入当前节点的答案,直接按照上面的方法异或就好了,如果要删除,其实也是按照上面的方法异或一次。
算一个二进制中1的个数,如果用bitset
,那么直接b.count()
就完事了,如果用位运算,可以参考下面的代码。
代码
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
struct edge{int to,nxt;}e[nmax<<1];
struct node2{int to,nxt; bool ans;}query[nmax];
int n,m,tot,head[nmax],deep[nmax],sz[nmax],son[nmax];
int qhead[nmax],num;
int cnt[nmax],nowadd;
bool visit[nmax];
char letter[nmax];
void add(int u, int v) {e[tot].to = v; e[tot].nxt = head[u]; head[u] = tot++;}
void add_query(int vertex, int deep) {
query[num].to = deep, query[num].nxt = qhead[vertex], qhead[vertex] = num++;
}
inline bool countone(int n){
int count = 0;
while(n) {n &= (n-1); count++; if(count > 1) return false; }
return true;
}
void dfs1(int u, int f, int d){
deep[u] = d; sz[u] = 1;
for(int i = head[u];i!=-1;i = e[i].nxt){
int v = e[i].to;
if(v != f){
dfs1(v,u,d+1);
sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
}
}
void update(int u, int f){
cnt[deep[u]] ^= (1<<(letter[u] - 'a'));
for(int i = head[u];i!=-1;i=e[i].nxt){
int v = e[i].to;
if(v != f && !visit[v]) update(v,u);
}
}
void dfs2(int u, int f, bool keep = false) {
for(int i = head[u];i!=-1;i = e[i].nxt){
int v = e[i].to;
if(v == f || v == son[u]) continue;
else dfs2(v,u);
}
if(son[u]) dfs2(son[u],u,true), visit[son[u]] = true;
update(u,f);
for(int i = qhead[u] ;i!=-1;i = query[i].nxt)query[i].ans = countone(cnt[query[i].to]);
if(son[u]) visit[son[u]] = false;
if(!keep) update(u,f);
}
int main(){
memset(head,-1,sizeof head);
memset(qhead,-1,sizeof qhead);
scanf("%d %d",&n,&m);
int v;
for(int u = 2;u<=n;++u){
scanf("%d",&v);
add(u,v), add(v,u);
}
scanf("%s",letter + 1);
int vertex, dee;
for(int i = 1;i<=m;++i) {
scanf("%d %d",&vertex,&dee);
add_query(vertex,dee);
}
dfs1(1,-1,1);
dfs2(1,-1);
for(int i = 0;i<m;++i) printf("%s\n",query[i].ans == true?"Yes":"No");
return 0;
}