……

1513 树上的回文

这题好妙啊,看讨论区很多做法,但我都不会^ ^

http://www.51nod.com/Question/Index.html#questionId=1542&isAsc=false

讨论区kczno1大佬的做法:

dfs一遍,每个深度记每个字母的奇偶性,这个用一个二进制数就可以了。
然后对每个询问 用该层进入子树前的数^退出子树时的数,判断它是否全0或者只有一个1 就好了。
 

 

/*input
6 5
1 1 1 3 3
zacccd
1 1
3 3
4 1
6 1
1 2
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

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

const int inf=0x3f3f3f3f;
const int maxn=5e5+50;

int n, m;
int cnt, max_h;
char s[maxn];
int high[maxn];
vector<int> G[maxn], A[maxn], B[maxn];
pair<int, int> dfn[maxn];//in out

void dfs(int u, int fa, int h){
    max_h = max(h, max_h);
    high[u] = h;
    dfn[u].first = ++cnt;
    A[h].push_back(1<<(s[u] - 'a'));
    B[h].push_back(cnt);

    for (auto v:G[u]) dfs(v, u, h + 1);

    dfn[u].second = cnt;
}

int solve(int x, int h){
    if (h <= high[x] || !B[h].size()) return 1;

    int l = (int)(lower_bound(B[h].begin(), B[h].end(), dfn[x].first) - B[h].begin());
    int r = (int)(upper_bound(B[h].begin(), B[h].end(), dfn[x].second) - B[h].begin() - 1);
    if (l > r)  return 1;

    int ans = A[h][r] ^ (l ? A[h][l - 1] : 0);
    if (ans == (ans & (-ans)))  return 1;//只能有1个1
    return 0;
}

int main(){
    n=read(), m=read();
    for (int i = 2,x; i <= n; i++){
        x=read();
        G[x].push_back(i);
    }

    scanf("%s", s+1);
    dfs(1,0,1);

    for (int i = 0; i <=max_h; i++)
        for (int j = 1; j < A[i].size(); j++)
            A[i][j] ^= A[i][j - 1];

    int v, h;
    while (m--) {
        v=read(), h=read();
        if (solve(v, h)) puts("Yes");
        else puts("No");
    }
    return 0;
}

 

posted @ 2021-02-14 16:25  noobimp  阅读(43)  评论(0编辑  收藏  举报