牛客练习赛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;
}
原文地址:https://www.cnblogs.com/Grice/p/12243992.html