[链分治][FWT][树链剖分] BZOJ 4911: [Sdoi2017]切树游戏

来源:互联网 发布:python获取svn版本号 编辑:程序博客网 时间:2024/06/06 17:15

Solution

DP是一个异或卷积的形式,可以FWT把O(128)的复杂度降下来。
链分治参考immortalCO的博客。
最后还是有些地方0的逆元的问题搞错了。。

#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;}