Codeforces Round #316 (Div.2)Tree Requests

又是莫名RE系列…
首先一个想法,就是把字母转化成一个二进制位,因为如果一个字符出现两次,那么它们就可以被配成一对,也就是说,这两个就和没有是一样的.
那这对我们有什么帮助呢?
那就和异或一样了,两个状态合并的同时,相同为0,不同为1,这样的话,最后合并出来的状态里有的二进制1的数量必定不大于1,这样的状态才可能被变成回文串.
所以加入和删除都是异或操作.
接下来就是怎么知道一棵子树下面的某一行的异或值和了.
参考这里,我们可以有一种方法来完成这个.
先把每个节点的重儿子找到,然后先去递归解决轻儿子,最后解决重儿子,但是把重儿子的值留下来,因为现在这个节点也会用到这个重儿子里面的所有信息,所以现在并不用删除.
然后计算这个节点的时候把所有的都加上去,最后出递归的时候再看一下它是不是重儿子,如果不是的话就把以它为根的这棵子树上的节点都去掉.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
#define M 1000005
using namespace std;
void Rd(int &res){
    res=0;char p;
    while(p=getchar(),p<'0');
    do{
        res=(res<<1)+(res<<3)+(p^48);
    }while(p=getchar(),p>='0');
}
struct W{
    int to,nx;
}Lis[M];
int Head[M],tot=0;
void Add(int x,int y){
    Lis[tot].to=y,Lis[tot].nx=Head[x],Head[x]=tot++;
}
struct T{
    int id,hi,nx;
}Q[M];
int rHead[M],rtot=0;
void rAdd(int x,int id,int hi){
    Q[rtot].id=id,Q[rtot].hi=hi,Q[rtot].nx=rHead[x],rHead[x]=rtot++;
}
char S[M];
bool ans[M],bigson[M];
int de[M],bin[32],cntson[M],Mxson[M];
int pl[M];
set<int>st;
void Init(int x){
    cntson[x]=1;
    Mxson[x]=0;
    int Mx=0;
    for(int i=Head[x],to;~i&&(to=Lis[i].to,1);i=Lis[i].nx){
        Init(to),cntson[x]+=cntson[to];
        if(cntson[to]>Mx)Mx=cntson[to],Mxson[x]=to;
    }
}
void add_ph(int x){
    pl[de[x]]^=bin[S[x]-'a'];
    for(int i=Head[x],to;~i&&(to=Lis[i].to,1);i=Lis[i].nx)
        if(!bigson[to])add_ph(to);
}
void dfs(int x,bool kep){
    for(int i=Head[x],to;~i&&(to=Lis[i].to,1);i=Lis[i].nx)
        if(to!=Mxson[x])dfs(to,0);

    if(Mxson[x]!=0)dfs(Mxson[x],1),bigson[Mxson[x]]=1;

    add_ph(x);

    for(int i=rHead[x],id,hi;~i&&(id=Q[i].id,hi=Q[i].hi,1);i=Q[i].nx)
        ans[id]=(st.find(pl[hi])!=st.end());

    if(Mxson[x]!=0)bigson[Mxson[x]]=0;

    if(!kep)add_ph(x);
}
int main(){
    memset(Head,-1,sizeof(Head));
    memset(rHead,-1,sizeof(rHead));
    for(int i=0;i<31;i++)bin[i]=(1<<i);
    for(int i=0;i<26;i++)st.insert(1<<i);st.insert(0);
    int n,m;Rd(n),Rd(m);
    de[1]=1;
    for(int i=2,x;i<=n;i++)Rd(x),Add(x,i),de[i]=de[x]+1;
    scanf("%s",S+1);
    for(int i=1,x,y;i<=m;i++)Rd(x),Rd(y),rAdd(x,i,y);
    Init(1);
    dfs(1,1);
    for(int i=1;i<=m;i++)
        if(ans[i])puts("Yes");
        else puts("No");
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值