[CF570D] Tree Requests

Description

给定一棵有根树,每个结点有一个字母,每个点的深度定义为到 (1) 号点的路径上的点的个数,每次询问 (a,b),查询以 (a) 为根的子树内深度为 (b) 的结点上的字母重新排列之后能否构成回文串。

Solution

条件等价于奇数结点个数不大于 (1)

离线处理,将询问挂在 (a)

对于每个子树,我们需要求的是子树内各个颜色结点的个数和

由于起作用的只有奇偶性,我们可以用一个 01 串记录状态,加减就是异或

考虑按 DFS 序做差,我们只需要在进入子树的时候记录一下状态,退出的时候将当前状态与记录异或一下即可

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000005;

int n,m,col[N],dep[N],ans[N],t1,t2;
bitset<26> s[N],rec[N];
vector <int> g[N];

struct request
{
    int a,b,id;
};

vector <request> r[N];

void print()
{
    cout<<" BEGIN"<<endl;
    for(int i=1;i<=3;i++)
    {
        cout<<"  "<<s[i]<<endl;
    }
    cout<<" END"<<endl;
}

void dfs(int p)
{
    //cout<<"> "<<p<<endl;
    //print();
    for(auto req:r[p])
    {
        int id=req.id;
        rec[id]=s[req.b];
    }

    s[dep[p]].flip(col[p]);
    for(int q:g[p])
    {
        dep[q]=dep[p]+1;
        dfs(q);
    }

    for(auto req:r[p])
    {
        int id=req.id;
        bitset<26> tmp=rec[id]^s[req.b];
        if(tmp.count()<=1) ans[id]=1;
    }
    //print();
    //cout<<"< "<<p<<endl;
}

signed main()
{
    ios::sync_with_stdio(false);

    cin>>n>>m;
    for(int i=1;i<n;i++)
    {
        cin>>t1;
        g[t1].push_back(i+1);
    }
    for(int i=1;i<=n;i++)
    {
        char c;
        cin>>c;
        col[i]=c-'a';
    }
    for(int i=1;i<=m;i++)
    {
        cin>>t1>>t2;
        r[t1].push_back({t1,t2,i});
    }
    dep[1]=1;
    dfs(1);
    for(int i=1;i<=m;i++)
    {
        if(ans[i]) puts("Yes");
        else puts("No");
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/13617845.html