570D Tree Requests (dsu_on_tree)

传送门:https://codeforces.com/contest/570/problem/D
题目大意:给一棵树,每个节点有一个字母,问节点v的深度为h的儿子节点的所有字母能否组成一个回文串(深度是对于整棵树)
很裸的一个树上合并,也可以使用二分来做

//919ms
#include
using namespace std;
const int maxn=5e5+5;
vector<int>e[maxn];
vectorint,int>>query[maxn];
int sz[maxn],depth[maxn],st[maxn],ed[maxn],pre[maxn];
int cnt[maxn][26],cnt2[maxn];
bool ans[maxn];
char str[maxn];
int n,m,dfs_clock;
void dfs1(int u,int dp)
{
    depth[u]=dp;
    sz[u]=1;
    st[u]=++dfs_clock;pre[dfs_clock]=u;
    for(auto v:e[u]){
        dfs1(v,dp+1);
        sz[u]+=sz[v];
    }
    ed[u]=dfs_clock;
}
void add(int u,int val)
{
    for(int i=st[u];i<=ed[u];i++){
        int v=pre[i];
        cnt[depth[v]][str[v]-'a']+=val;
        if(cnt[depth[v]][str[v]-'a']&1) cnt2[depth[v]]++;
        else cnt2[depth[v]]--;
    }
}
void dfs2(int u,bool keep)
{
    int maxx=-1,bigson=-1;
    for(auto v:e[u]){
        if(sz[v]>maxx){
            maxx=sz[v];
            bigson=v;
        }
    }
    for(auto v:e[u]){
        if(v==bigson) continue;
        dfs2(v,false);
    }
    if(bigson!=-1) dfs2(bigson,true);
    for(auto v:e[u])
        if(v!=bigson) add(v,1);
    cnt[depth[u]][str[u]-'a']++;
    if(cnt[depth[u]][str[u]-'a']&1) cnt2[depth[u]]++;
    else cnt2[depth[u]]--;
    for(auto it:query[u]){
        ans[it.second]=cnt2[it.first]<=1;
    }
    if(!keep) add(u,-1);
}
int main()
{
    freopen("in","r",stdin);
    freopen("out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=2;i<=n;i++){
        int v;
        scanf("%d",&v);
        e[v].push_back(i);
    }
    scanf("%s",str+1);
    for(int i=1;i<=m;i++){
        int v,h;
        scanf("%d%d",&v,&h);
        query[v].emplace_back(h,i);
    }
    dfs1(1,1);
    dfs2(1,false);
    for(int i=1;i<=m;i++)
        if(ans[i]) puts("Yes");
        else puts("No");
    return 0;
}

你可能感兴趣的:(数据结构)