Codeforces 570D

http://codeforces.com/contest/570/problem/D

给一棵有根树(50w个点)(指定根是1号节点),每个点上有一个小写字母,然后有最多50w个询问,每个询问给出x和f,表示询问以x为根的子树,在第f层的所有节点上的字符能否组成一个回文串

首先树形转线性,把每个点按照DFS序重新标号,然后开个vector记下第i层都有哪些节点,

对于这一层的节点,维护一个前缀和,即某个字母出现过多少次,

这样对于某个询问x,f,我们能知道x为根的子树在线性数组中的序号范围,

然后二分查找第f层位于这个范围的点,通过前缀和就很容易求出来某个字母出现过多少次

因为回文串中最多有一个字母出现奇数次,所以就可以判断是否是回文串。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#include<string>
#include<sstream>
#define eps 1e-9
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define MAXN 500005
#define MAXM 40005
#define INF 0x3fffffff
#define PB push_back
#define MP make_pair
#define X first
#define Y second
#define clr(x,y) memset(x,y,sizeof(x));
using namespace std;
typedef long long LL;
int i,j,k,n,m,x,y,T,ans,big,cas,num,len;
bool flag;

vector<int> G[MAXN],D[MAXN];
int op[MAXN],ed[MAXN],lin[MAXN],d[MAXN],mxdp;
int ti[MAXN][26];
char s[MAXN];
int p[30];

void dfs(int u,int f)
{
    d[u]=f;
    mxdp=max(mxdp,f);
    lin[num]=u;//线性数组 
    op[u]=num;//子树的起始位置
    D[f].PB(num); //D[f]表示f层都有哪些节点
    num++;
    for (int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        dfs(v,f+1);
    }
    ed[u]=num-1;//子树的终止位置
}


int main()
{
    scanf("%d%d",&n,&m);
    for (i=2;i<=n;i++)
    {
        scanf("%d",&x);
        G[x].PB(i);
    }
    scanf("%s",s+1);
    for (i=1;i<=n;i++) D[i].PB(0);
    num=1;
    dfs(1,1);
    for (i=1;i<=mxdp;i++)
    {
        for (j=1;j<D[i].size();j++)
        {
            int u=D[i][j-1];
            int v=D[i][j];
            for (k=0;k<26;k++) ti[v][k]=ti[u][k];//ti[u][k]表示节点u所在的那一层,从开始到节点u,各个字母出现的次数

            ti[v][s[ lin[v]  ]-'a']++;
        }
    }

    for (i=1;i<=m;i++)
    {
        int u,f;
        scanf("%d%d",&u,&f);
        int l=op[u],r=ed[u];
        int s=upper_bound(D[f].begin(),D[f].end(),l)-D[f].begin()-1;
        int e=upper_bound(D[f].begin(),D[f].end(),r)-D[f].begin()-1;
        if (s>=e)
        {
            printf("Yes
");
        }else
        {
            int cnt=0;
            e=D[f][e];
            s=D[f][s];
            for (k=0;k<26;k++)
                if ((ti[e][k]-ti[s][k]) %2 ) cnt++;
            if (cnt>1) printf("No
");
            else printf("Yes
");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zhyfzy/p/4760497.html