CodeForces - 570D Tree Requests (树上启发式合并)

CodeForces - 570D 

题目大意:给出一个节点u问,节点u的子树中在深度为h的节点能不能组成一个回文串。

解题思路:寒假训练赛的一个题目,当时也不会,补题的时候用dfs序+二分写的。后来发现能用启发式合并写。

当时二分差点挂了,果然树上启发式合并跑的飞快。。。。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define sca(x) scanf("%d",&x)
#define pb(x) push_back(x)
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define N 500005
#define mp(x,y) make_pair(x,y)

typedef pair<int,int>pii;
vector<pair<int,int>>V[N];
vector<int>G[N];
char s[N];
int sz[N],son[N];
int s1[N],dep[N];
int cnt[N][26];
int Son;
int ans[N];

void dfs1(int u,int de)
{
    sz[u]=1;
    dep[u]=de;
    int mx=-1;
    for(auto v:G[u]){
        dfs1(v,de+1);
        sz[u]+=sz[v];
        if(sz[v]>mx)mx=sz[v],son[u]=v;
    }
}

void add(int u,int val)
{
    cnt[dep[u]][s1[u]]+=val;
    for(auto v:G[u]){
        if(v!=Son){
            add(v,val);
        }
    }
}

void dfs(int u,int f)
{
    for(auto i:G[u]){
        if(i==son[u])continue;
        dfs(i,0);
    }
    if(son[u])dfs(son[u],1),Son=son[u];
    add(u,1);
    for(auto i:V[u])
    {
        int tmp=0,flag=0;
        for(int j=1;j<=26;j++)
        {
            if(cnt[i.first][j]&1)
            {
                tmp++;
            }
            if(tmp>=2)
            {
                ans[i.second]=0;
                flag=1;
            }
        }
        if(!flag)ans[i.second]=1;
    }
    if(son[u])Son=0;
    if(!f)add(u,-1);
}


int main()
{
    int n,m;
    sca(n),sca(m);
    for(int i=2;i<=n;i++)
    {
        int tmp;
        sca(tmp);
        G[tmp].pb(i);
    }
    scanf("%s",s+1);
    rep(i,1,n)s1[i]=s[i]-'a'+1;
    dfs1(1,1);
    for(int i=1;i<=m;i++)
    {
        int x,h;
        sca(x),sca(h);
        V[x].pb(mp(h,i));
    }
    dfs(1,1);
    rep(i,1,m)puts(ans[i]?"Yes":"No");
}

猜你喜欢

转载自blog.csdn.net/weixin_40894017/article/details/88737009
今日推荐