[LOJ # 3044] [Dynamic DP] "ZJOI2019" Minimax search

  • Topic Portal

  • Easy to think of violence DP: For each first into \ (K \) obtaining \ (\ max_ {i \ in S} | i-w_i | \ le k \) program number, the last difference

  • The question then converted to a weight of each leaf has a value interval, then we can note that the value of the weight of each point into \ (<W is, W is =,> W is \) (considered \ (0,1, 2 \) ) three types of treatment and then the DP \ (F [U] [0/1/2] \)

  • Then you will soon find that do not, because when some selected set of leaf, root weights may be less than \ (W is \) may be larger than \ (W is \) , directly \ (2 ^ m-1 \ ) subtracting \ (f [u] [0 ] + f [u] [2] \) can not get the correct result

  • So we try to consider how the \ (<\ W) and \ (> W \) remove one of these two conditions

  • Consider a weight of \ (W \) a chain leaf to the root

  • Easy to find root weights will be changed, if and when this point there is only one strand will be changed

  • On this chain there is provided a depth point odd \ (U \) (even-numbered Similarly), after considering all side chain are deleted (U \) \ where the communication block

  • Readily available in the original tree \ (U \) is changed weights, if and only if after Erase on \ (U \) communication block is located , let \ (U \) weights greater than \ (W is \ )

  • Particularly, if the \ (U \) is a leaf then the \ (U \) weights are changed if and only if \ (U \) in the selected set and \ (k> 0 \)

  • So that we achieved in the \ (<W \) and \ (> W \) remove one of these two conditions

  • We have a DP: \ (f [U] \) represents \ (u \) leaves in the sub-tree node how many subsets let \ (u \) weights greater than \ (W \)

  • If \ (U \) (depth of odd \ (CNT_U \) of \ (U \) leaves the number of sub-tree):

  • \[f[u]=2^{cnt_u}-\prod_{v\in son[u]}(2^{cnt_v}-f[v])\]

  • otherwise:

  • \[f[u]=\prod_{v\in son[u]}f[v]\]

  • The result of all DP block communication with \ (2 ^ {cnt} \ ) after subtracting take up, the root node is the weight not changed the number of programs

  • For each \ (K \) complexity is performed DP \ (O (n ^ 2) \)

  • Consider how to optimize. We note that this transfer and DP (k \) \ unrelated, only the initial value (leaves) and \ (k \) related

  • If a point \ (U \) depth where communication roots in the original tree is odd, then the point \ (U \) is the initial value should be:

  • \[f[u]=[u>W]+[u+k>W]\]

  • Note that when \ (k \) continues to add a time, \ ([U + k> W] \) changes only once

  • Thus ascending enumeration \ (K \) after moving to DP

  • Note Because of \ (f [u] \) may be \ (0 \) , when it is not the updated value DP up \ (f [fa [u] ] \) is directly divided by \ (f [u] \) , the need to maintain a variable each point represents the value of the sub node DP how many \ (0 \) , the other variable represents the child node is \ (0 \) product of value DP

  • \(O(n\log^2n)\)

Code

#include <bits/stdc++.h>
#define p2 p << 1
#define p3 p << 1 | 1

template <class T>
inline void read(T &res)
{
    res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    if (bo) res = ~res + 1;
}

template <class T>
inline T Min(const T &a, const T &b) {return a < b ? a : b;}

template <class T>
inline T Max(const T &a, const T &b) {return a > b ? a : b;}

const int N = 2e5 + 5, M = N << 1, L = M << 1, rqy = 998244353;

int n, l, r, dep[N], ecnt, nxt[M], adj[N], go[M], val[N], ans[N], f[N], cnt[N],
fa[N], sze[N], son[N], top[N], pos[N], idx[N], bot[N], QAQ, pw[N], re[N], c0[N],
rea = 1, cnt0;
bool lea[N], bel[N];

int qpow(int a, int b)
{
    int res = 1;
    while (b)
    {
        if (b & 1) res = 1ll * res * a % rqy;
        a = 1ll * a * a % rqy;
        b >>= 1;
    }
    return res;
}

struct modi
{
    int a, b;
    
    friend inline modi operator * (modi x, modi y)
    {
        return (modi) {(int) (1ll * x.a * y.a % rqy),
            (int) ((1ll * x.a * y.b + x.b) % rqy)};
    }
    
    friend inline int operator * (modi x, int y)
    {
        return (1ll * x.a * y + x.b) % rqy;
    }
} g[N], gp[L];

void add_edge(int u, int v)
{
    nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
    nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}

void dfs(int u, int fu)
{
    dep[u] = dep[fu] + 1;
    val[u] = dep[u] & 1 ? 1 : n;
    bool is = 1;
    for (int e = adj[u], v; e; e = nxt[e])
        if ((v = go[e]) != fu)
        {
            dfs(v, u); is = 0;
            if (dep[u] & 1) val[u] = Max(val[u], val[v]);
            else val[u] = Min(val[u], val[v]);
        }
    if (is) lea[val[u] = u] = 1, ans[0] = (ans[0] + ans[0]) % rqy;
}

void dfs1(int u, int fu, bool op)
{
    fa[u] = fu; sze[u] = 1; bel[u] = op; cnt[u] = lea[u];
    for (int e = adj[u], v; e; e = nxt[e])
        if ((v = go[e]) != fu && val[v] != val[1])
        {
            dfs1(v, u, op);
            sze[u] += sze[v]; cnt[u] += cnt[v];
            if (sze[v] > sze[son[u]]) son[u] = v;
        }
    f[u] = (op ? val[u] > val[1] : val[u] < val[1]) ? pw[cnt[u]] : 0;
    g[u].a = re[u] = 1;
    if ((dep[u] & 1) ^ op)
    {
        for (int e = adj[u], v; e; e = nxt[e])
            if ((v = go[e]) != fu && val[v] != val[1] && v != son[u])
            {
                g[u].a = 1ll * g[u].a * f[v] % rqy;
                if (f[v]) re[u] = 1ll * re[u] * f[v] % rqy; else c0[u]++;
            }
    }
    else
    {
        for (int e = adj[u], v; e; e = nxt[e])
            if ((v = go[e]) != fu && val[v] != val[1] && v != son[u])
            {
                int tmp = (pw[cnt[v]] - f[v] + rqy) % rqy;
                g[u].a = 1ll * g[u].a * tmp % rqy;
                if (tmp) re[u] = 1ll * re[u] * tmp % rqy; else c0[u]++;
            }
        g[u].b = (pw[cnt[u]] - 1ll * g[u].a * pw[cnt[son[u]]] % rqy + rqy) % rqy;
    }
    bot[u] = son[u] ? bot[son[u]] : u;
}

void dfs2(int u, int fu)
{
    if (son[u])
    {
        top[son[u]] = top[u];
        idx[pos[son[u]] = ++QAQ] = son[u];
        dfs2(son[u], u);
    }
    for (int e = adj[u], v; e; e = nxt[e])
        if ((v = go[e]) != fu && v != son[u] && val[v] != val[1])
            top[v] = v, idx[pos[v] = ++QAQ] = v, dfs2(v, u);
}

void build(int l, int r, int p)
{
    if (l == r) return (void) (gp[p] = g[idx[l]]);
    int mid = l + r >> 1;
    build(l, mid, p2); build(mid + 1, r, p3);
    gp[p] = gp[p2] * gp[p3];
}

void change(int l, int r, int pos, modi v, int p)
{
    if (l == r) return (void) (gp[p] = v);
    int mid = l + r >> 1;
    if (pos <= mid) change(l, mid, pos, v, p2);
    else change(mid + 1, r, pos, v, p3);
    gp[p] = gp[p2] * gp[p3];
}

modi ask(int l, int r, int s, int e, int p)
{
    if (e < l || s > r) return (modi) {1, 0};
    if (s <= l && r <= e) return gp[p];
    int mid = l + r >> 1;
    return ask(l, mid, s, e, p2) * ask(mid + 1, r, s, e, p3);
}

void modify(int u, int x)
{
    bool fi = 1; int of;
    while (1)
    {
        int v = top[u], w = fa[v], rf = f[v], nf;
        if (fi) fi = 0, f[u] = x; nf = f[v];
        if (v != bot[u]) nf = f[v] =
            ask(1, n, pos[v], pos[bot[u]] - 1, 1) * f[bot[u]] % rqy;
        if (!w) {of = rf; u = v; break;}
        if ((dep[v] & 1) ^ bel[v]) rf = (pw[cnt[v]] - rf + rqy) % rqy,
            nf = (pw[cnt[v]] - nf + rqy) % rqy;
        if (!rf) c0[w]--; else re[w] = 1ll * re[w] * qpow(rf, rqy - 2) % rqy;
        if (!nf) c0[w]++; else re[w] = 1ll * re[w] * nf % rqy;
        g[w].a = c0[w] ? 0 : re[w];
        g[w].b = (dep[w] & 1) ^ bel[w] ? 0 : (pw[cnt[w]] -
            1ll * g[w].a * pw[cnt[son[w]]] % rqy + rqy) % rqy;
        change(1, n, pos[w], g[w], 1);
        u = w;
    }
    if (of == pw[cnt[u]]) cnt0--; else rea = 1ll * rea *
        qpow(pw[cnt[u]] - of + rqy, rqy - 2) % rqy;
    if (f[u] == pw[cnt[u]]) cnt0++;
        else rea = 1ll * rea * (pw[cnt[u]] - f[u] + rqy) % rqy;
}

int main()
{
    int x, y;
    read(n); read(l); read(r);
    for (int i = 1; i < n; i++)
        read(x), read(y), add_edge(x, y);
    ans[0] = pw[0] = ans[n] = 1; dfs(1, 0);
    for (int i = 1; i <= n; i++) pw[i] = (pw[i - 1] + pw[i - 1]) % rqy;
    rea = 499122177ll * ans[0] % rqy;
    for (int u = 1; u <= n; u++)
    {
        if (val[u] != val[1] || u == val[1]) continue;
        dfs1(u, 0, dep[u] & 1);
        if (!cnt[u] || lea[u]) continue;
        idx[pos[u] = ++QAQ] = top[u] = u;
        dfs2(u, 0);
    }
    build(1, n, 1);
    for (int i = 1; i < n; i++)
    {
        if (i > 1 && val[1] >= i && lea[val[1] - i + 1] && bel[val[1] - i + 1])
            modify(val[1] - i + 1, 1);
        if (i > 1 && val[1] <= n - i + 1 && lea[val[1] + i - 1]
            && !bel[val[1] + i - 1]) modify(val[1] + i - 1, 1);
        ans[i] = cnt0 ? 0 : rea;
    }
    for (int i = l; i <= r; i++) printf("%d ", (ans[i - 1] - ans[i] + rqy) % rqy);
    return puts(""), 0;
}

Guess you like

Origin www.cnblogs.com/xyz32768/p/12040207.html