牛客练习赛57-划分树
题意
做法
我们只考虑\(0\)跟\(M\)这部分的贡献
\(dp[u][0/1]\)为割掉与儿子偶数/奇数为\(M\)的子树异或和
在保证下面为\(M\)的联通块的情况下,维护新的方案
题外话
感觉有点神仙的样子,鸽了好久才补上来
代码比较简单,放的\(std\)
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 500003, mod = 1004535809;
typedef long long ll;
ll dp[N][2];
struct Edge {
int v, nxt;
} G[N]; int head[N], a[N], M;
void adde(int u, int v) {
G[++head[0]] = (Edge) {v, head[u]}; head[u] = head[0];
}
void dfs(int u) {
dp[u][0] = 1;
ll dpu0, dpu1;
for (int i = head[u]; i; i = G[i].nxt) {
int v = G[i].v;
dfs(v);
a[u] ^= a[v];
dpu0 = dp[u][0], dpu1 = dp[u][1];
dp[u][0] = (dpu0 * dp[v][0] + dpu1 * dp[v][1]) % mod;
dp[u][1] = (dpu0 * dp[v][1] + dpu1 * dp[v][0]) % mod;
}
dpu0 = dp[u][0], dpu1 = dp[u][1];
if (u == 1) cout << (dpu0 * (a[u] == M) + dpu1 * (a[u] == 0)) % mod;
//和父亲的边
if (a[u] == 0) (dp[u][0] += dpu1) %= mod;
if (a[u] == M) (dp[u][1] += dpu0) %= mod;
}
int main() {
int n;
scanf("%d%d", &n, &M);
for (int u, i = 2; i <= n; i++) scanf("%d", &u), adde(u, i);
for (int i = 1; i <= n; ++i) scanf("%d", a + i);
dfs(1);
return 0;
}