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; }
Stay Hungry, Stay Foolish