Tree Requests

Tree Requests

https://ac.nowcoder.com/acm/problem/111044

题意

给你一棵有 个节点以 为根的树,每个节点为 的任意字母。有 次询问,每次询问给出 ,指以 为根的子树内深度为 的所有节点的字母在排列后能否构成一个回文串。

分析

要排列后成为回文串,所以在符合条件的所有节点之中至多只有一种字母的数量为奇数个,其余的字母数量必定均为偶数个。
因为回文串的总长如果为偶数,那么所有的字母必定成对(即偶数个)出现;如果长度为奇数,那么只会有一个字母有奇数个,其余均为偶数。

之后就是基本的 的操作了,先将所有的询问以离线的方式存储下来,这样我们就可以一边,一边解决所有的询问,之后统计所有深度,字母的出现次数以便我们的 ,再将轻边子树的信息保留到重链之上进行一个答案的统计。

代码

#include<bits/stdc++.h>
#define ll long long
const int N=1e6+5,INF=0x3f3f3f3f,mod=998244353;
using namespace std;

int n,m,cnt;
int head[N],siz[N],sum[N],son[N],dep[N],ans[N],tot[N][26];
bool vis[N];
char s[N];
struct node
{
    int to,nxt;
}e[N<<1];
struct rec
{
    int k,id;
};
std::vector<rec> q[N];

inline int read()
{
    register int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}

int qpow(int a,int b)
{
    int ans=1;
    while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}
    return ans;
}

void add(int u,int v)
{
    e[++cnt].nxt=head[u];
    e[cnt].to=v;
    head[u]=cnt;
}

void dfs(int x,int fa)
{
    siz[x]=1;dep[x]=dep[fa]+1;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa)    continue ;
        dfs(v,x);siz[x]+=siz[v];
        if(!son[x]||siz[v]>siz[son[x]])    son[x]=v;
    }
}

void calc(int x,int fa,int val)
{
    tot[dep[x]][s[x]-'a']+=val;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa||vis[v])    continue ;
        calc(v,x,val);
    }
}

bool check(int s[])
{
    int r=0;
    for(int i=0;i<26;i++)
    {
        if(s[i]&1) ++r;
        if(r>1)    return 0;
    }
    if(r>1)    return 0;
    return 1;
}

void dfs2(int x,int fa,int keep)
{
    for(int i=head[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa||v==son[x])    continue;
        dfs2(v,x,0);
    }
    if(son[x])    dfs2(son[x],x,1),vis[son[x]]=1;
    calc(x,fa,1),vis[son[x]]=0;
    for(int i=0;i<q[x].size();i++)    ans[q[x][i].id]=check(tot[q[x][i].k]);
    if(!keep)    calc(x,fa,-1);
}

int main()
{
    n=read();m=read();
    for(int i=2;i<=n;i++)
    {
        int u=read();
        add(u,i);add(i,u);
    }
    scanf("%s",s+1);
    dfs(1,0);
    for(int i=1;i<=m;i++)
    {
        int a=read(),b=read();
        q[a].push_back((rec){b,i});
    }
    dfs2(1,0,0);
    for(int i=1;i<=m;i++)
     if(ans[i])    printf("Yes\n");
     else printf("No\n");
    return 0;
}
全部评论

相关推荐

学java时间比较短不到三个月,基本的技术栈都过了一遍就是都不太深,有个小项目。是继续找实习还是沉淀准备秋招呢?找实习的话会花很多时间在八股,放弃的话又怕秋招简历太难看。有无大佬支招
今天java了吗:1.一定要找实习,实习不一定要去,但是找实习过程中的面试经验和心态经验才是最重要的 2.八股本来就是大头,甚至比项目重要 3.这个时间段也是面试比较多的阶段,可以抓住机会锻炼。面试才会发现自己的不足,感觉自己会了和能给面试官娓娓道来是两码事
点赞 评论 收藏
分享
05-19 19:57
蚌埠学院 Python
2237:Gpa70不算高,建议只写排名,个人技能不在多而在精,缩到8条以内。项目留一个含金量高的,减少间距弄到一页,硕士简历也就一页,本科不要写很多
点赞 评论 收藏
分享
一表renzha:你点进去没打招呼他也会有提示的,之前我点进美的,还没打招呼,他马上给我发了不太合适哦
点赞 评论 收藏
分享
评论
4
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务