【CF 570D】Tree Requests

【CF 570D】Tree Requests

树节点标号递增 规定父亲标号<儿子
dfs重标号 同时用一个数组存该节点为根的树的最小节点 一个数组存该节点为树根的最大节点 一个数组存对应深度存在的节点 再来一个数组存每一位置累计字符(26个字符 由于偶数次可压缩 故用异或即可)
每查询一个节点和他对应的深度 只需在该深度查该节点为根的最小和最大节点 然后用左右节点字符累计数互相异或 最后看它二进制存在几个奇数 两个以上便无法成回文。。
代码写挫了 胆小慎点

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f

using namespace std;

typedef struct Edge
{
    int v,next;
}Edge;

char str[500005];
set <int> dep[500001];
set <int>::iterator it;
Edge eg[500000];
int head[500001],hn[500001];
int in[500001],out[500001];
int num[500001],inh[500001];
int aa[500001];
int tp,cnt;

void dfs(int site,int h)
{
    in[site] = ++cnt;
    aa[cnt] = site;
    dep[h].insert(cnt);
    num[in[site]] = num[inh[h]]^(1<<(str[site]-'a'));
    inh[h] = in[site];
    int i;
    for(i = head[site]; i != -1; i = eg[i].next)
    {
        dfs(eg[i].v,h+1);
    }
    out[site] = cnt;
}

int main()
{
    int n,m,i,x,u,h,l,r,tmp;
    scanf("%d %d",&n,&m);
    tp = 0;
    cnt = 0;


    memset(head,-1,sizeof(head));
    memset(hn,-1,sizeof(hn));
    for(i = 2; i <= n; ++i)
    {
        scanf("%d",&x);
        if(hn[x] == -1)  head[x] = tp;
        else eg[hn[x]].next = tp;
        eg[tp].v = i;
        eg[tp].next = -1;
        hn[x] = tp++;
    }


    for(i = 1; i  <= 500000; ++i)
    {
        dep[i].insert(0);
        dep[i].insert(INF);
    }
    memset(inh,0,sizeof(inh));
    memset(num,0,sizeof(num));


    scanf("%s",str+1);
    dfs(1,1);


    while(m--)
    {
        scanf("%d %d",&u,&h);
        l = *dep[h].lower_bound(in[u]);
        it = dep[h].lower_bound(out[u]);
        if(*it != out[u]) --it;
       // printf("%d %d %d %d\n",l,*it,num[l],num[*it]);
        if(l <= in[u] || *it <= in[u]) puts("Yes");
        else
        {
            l = num[l]^(num[*it])^(1<<(str[aa[l]]-'a'));
            tmp = 0;
            while(l)
            {
                if(l&1) tmp++;
                l >>= 1;
            }
            if(tmp > 1) puts("No");
            else puts("Yes");
        }
    }
    return 0;
}

你可能感兴趣的:(重标号区间遍历)