Codeforces 570D - Tree Requests - [DFS序+二分]

題目連接:https://codeforces.com/problemset/problem/570/Dc++

 

題解:數組

這種題,基本上容易想到DFS序。spa

而後,咱們若是再把全部節點分層存下來,那麼顯然能夠根據 $in[v],out[v]$ 在層內二分出一段屬於 $v$ 的子樹的節點。code

那麼咱們進一步考慮,若是把一層的節點,按 $a \sim z$ 再分開來,用一個 $S[c][d]$ 數組來存全部字母爲 $c$,深度爲 $d$ 的節點的 $in[]$ 值。blog

這樣一來,對於一個詢問 $v,h$,就在 $S[c][h]$ 二分找到屬於區間 $[in[v],out[v]]$ 的那一段,這一段的長度若是爲 $r$,說明 $v$ 節點的子樹中、深度爲 $h$ 的、字母爲 $c$ 的節點有 $r$ 個,get

這個 $r$ 若爲偶數,那麼必然能夠用來組成迴文串;若是爲奇數,那麼最多隻能一個字母的個數是奇數,不然就不能組成迴文串了。it

 

AC代碼:class

#include<bits/stdc++.h>
#define pb(x) push_back(x)
using namespace std;
typedef pair<int,int> P;
#define fi first
#define se second
const int maxn=5e5+10;

int n,m;
char c[maxn];
int d[maxn];
vector<int> G[maxn];
vector<int> S[26][maxn];

int clk;
int maxd;
int in[maxn],out[maxn];
void dfs(int x,int depth)
{
    in[x]=++clk;
    maxd=max(maxd,depth);
    S[c[x]-'a'][d[x]=depth].pb(in[x]);
    for(auto y:G[x]) dfs(y,depth+1);
    out[x]=clk;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int y=2,x;y<=n;y++)
    {
        scanf("%d",&x);
        G[x].pb(y);
    }
    scanf("%s",c+1);

    clk=0, maxd=0, dfs(1,1);

    while(m--)
    {
        int v,h; scanf("%d%d",&v,&h);
        if(d[v]>=h)
        {
            printf("Yes\n");
            continue;
        }

        int cnt=0;
        for(int i=0;i<26;i++)
        {
            int L=lower_bound(S[i][h].begin(),S[i][h].end(),in[v])-S[i][h].begin();
            int R=upper_bound(S[i][h].begin(),S[i][h].end(),out[v])-S[i][h].begin();
            cnt+=(R-L)%2;
        }
        if(cnt>1) printf("No\n");
        else printf("Yes\n");
    }
}
相關文章
相關標籤/搜索