Solution
DP是一个异或卷积的形式,可以FWT把
O(128)
的复杂度降下来。
链分治参考immortalCO的博客。
最后还是有些地方
0
<script type="math/tex" id="MathJax-Element-88">0</script>的逆元的问题搞错了。。
#include <bits/stdc++.h>
using namespace std;
const int N = 60303;
const int M = 130;
const int MOD = 10007;
const int INV2 = (MOD + 1) >> 1;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
template<typename T>
inline void read(T &x) {
static char c; x = 0; int sgn = 0;
for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1;
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
if (sgn) x = -x;
}
inline void reado(char &c) {
for (c = get(); c != 'Q' && c != 'C'; c = get());
}
struct edge {
int to, next;
edge(int t = 0, int n = 0):to(t), next(n) {}
};
edge G[N << 1];
int head[N];
int Gcnt, Tcnt, n, m, q, x, y, lim, tnt;
int top[N], size[N], son[N], fa[N], dep[N];
int inv[N], pos[N], tps[N], w[N];
vector<int> s[N];
struct Int {
int d, c;
Int(void) {}
Int(int x) {
x %= MOD;
if (x) d = x, c = 0;
else d = 1, c = 1;
}
inline Int &operator *=(int x) {
x %= MOD; if (x == 0) ++c;
else d = d * x % MOD;
return *this;
}
inline Int &operator /=(int x) {
x %= MOD; if (x == 0) --c;
else d = d * inv[x] % MOD;
return *this;
}
inline int val(void) {
return c ? 0 : d;
}
};
int num[M][M];
Int lt[N][M];
int rt[N], ans[N], res[N];
int sum[N * 3][M], lval[N * 3][M], rval[N * 3][M], val[N * 3][M];
int ls[N * 3], rs[N * 3], par[N * 3];
char opt;
inline void Add(int &x, int a) {
x = (x + a) % MOD;
}
inline void AddEdge(int from, int to) {
G[++Gcnt] = edge(from, head[to]); head[to] = Gcnt;
G[++Gcnt] = edge(to, head[from]); head[from] = Gcnt;
}
inline void dfs1(int u) {
int to; size[u] = 1;
for (int i = head[u]; i; i = G[i].next) {
to = G[i].to; if (to == fa[u]) continue;
fa[to] = u; dep[to] = dep[u] + 1;
dfs1(to); size[u] += size[to];
if (size[to] > size[son[u]]) son[u] = to;
}
}
inline void dfs2(int u, int t) {
top[u] = t; s[t].push_back(u);
if (son[u]) dfs2(son[u], t);
for (int i = head[u]; i; i = G[i].next)
if (G[i].to != fa[u] && G[i].to != son[u])
dfs2(G[i].to, G[i].to);
}
inline void FWT(int* a, int n, int f) {
static int x, y;
for (int i = 1; i < n; i <<= 1)
for (int j = 0; j < n; j += (i << 1))
for (int k = 0; k < i; k++) {
x = a[j + k]; y = a[j + k + i];
a[j + k] = (x + y) % MOD;
a[j + k + i] = (x - y + MOD) % MOD;
if (f == -1) {
a[j + k] = a[j + k] * INV2 % MOD;
a[j + k + i] = a[j + k + i] * INV2 % MOD;
}
}
}
inline void Prep(int m) {
inv[1] = 1;
for (int i = 2; i < MOD; i++)
inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
for (int i = 0; i < m; i++) {
num[i][i] = 1; FWT(num[i], m, 1);
}
}
inline void PushUp(int o) {
int L = ls[o], R = rs[o];
for (int i = 0; i < lim; i++) {
val[o][i] = (val[L][i] + val[R][i] + rval[L][i] * lval[R][i]) % MOD;
lval[o][i] = (lval[L][i] + lval[R][i] * sum[L][i]) % MOD;
rval[o][i] = (rval[R][i] + rval[L][i] * sum[R][i]) % MOD;
sum[o][i] = sum[L][i] * sum[R][i] % MOD;
}
}
inline void Build(int &o, int l, int r, int t) {
o = ++Tcnt;
if (l == r) {
for (int i = 0; i < lim; i++)
sum[o][i] = lval[o][i] = rval[o][i] =
val[o][i] = lt[s[t][l - 1]][i].val();
pos[s[t][l - 1]] = o; return;
}
int mid = (l + r) >> 1;
Build(ls[o], l, mid, t);
Build(rs[o], mid + 1, r, t);
PushUp(o); par[ls[o]] = par[rs[o]] = o;
}
inline void Modify(int u) {
int t = top[u];
if (fa[t])
for (int i = 0; i < lim; i++)
lt[fa[t]][i] /= (lval[rt[t]][i] + num[0][i]) % MOD;
for (int i = 0; i < lim; i++)
Add(ans[i], MOD - val[rt[t]][i]);
int o = pos[u];
for (int i = 0; i < lim; i++)
sum[o][i] = lval[o][i] = rval[o][i] =
val[o][i] = lt[u][i].val();
o = par[o];
while (o) {
PushUp(o); o = par[o];
}
if (fa[t])
for (int i = 0; i < lim; i++)
lt[fa[t]][i] *= (lval[rt[t]][i] + num[0][i]) % MOD;
for (int i = 0; i < lim; i++)
Add(ans[i], val[rt[t]][i]);
}
inline bool cmp(int x, int y) {
return dep[x] > dep[y];
}
int main(void) {
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
read(n); read(m);
for (lim = 1; lim < m; lim <<= 1);
Prep(lim);
for (int i = 1; i <= n; i++) {
read(w[i]);
for (int j = 0; j < lim; j++)
lt[i][j] = Int(num[w[i]][j]);
}
for (int i = 1; i < n; i++) {
read(x); read(y);
AddEdge(x, y);
}
dfs1(1); dfs2(1, 1);
for (int i = 1; i <= n; i++)
if (top[i] == i) tps[++tnt] = i;
sort(tps + 1, tps + tnt + 1, cmp);
for (int i = 1; i <= tnt; i++) {
int x = tps[i];
Build(rt[x], 1, s[x].size(), x);
if (fa[x])
for (int j = 0; j < lim; j++)
lt[fa[x]][j] *= (lval[rt[x]][j] + num[0][j]) % MOD;
for (int j = 0; j < lim; j++)
Add(ans[j], val[rt[x]][j]);
}
read(q);
while (q--) {
reado(opt);
if (opt == 'C') {
read(x); read(y);
for (int i = 0; i < lim; i++)
lt[x][i] /= num[w[x]][i];
w[x] = y;
for (int i = 0; i < lim; i++)
lt[x][i] *= num[w[x]][i];
while (x) {
Modify(x); x = fa[top[x]];
}
} else {
read(x);
for (int i = 0; i < lim; i++) res[i] = ans[i];
FWT(res, lim, -1);
printf("%d\n", res[x]);
}
}
return 0;
}