noip2018 保卫王国

动态维护树上最小点覆盖

$n \leq 100000$

sol:动态 dp,请

先写一个树上的 dp

$f_{(x,0)} = \sum f_{(to,1)}$

$f_{(x,1)} = v_x + \sum f_{(to,0)}$

首先考虑链上的情形

链上的转移方程非常的清真,它是

$f_{(x,0)} = f_{(to,1)}$

$f_{(x,1)} = v_x + f_{(to,0)}$

$to$ 就是 $x$ 左边的点

这个方程是一个广义的常系数线性递推(把 min 看成线性),可以用一个广义的矩阵来维护

维护一个矩阵 $ \left[ \begin{matrix} 0 & \infty \\ v_x & v_x \end{matrix} \right]$

则 $ \left[ \begin{matrix} 0 & \infty \\ v_x & v_x \end{matrix} \right] \times \left[ \begin{matrix} f_{(x-1,0)} \\ f_{(x-1,1)} \end{matrix} \right] = \left[ \begin{matrix} f_{(x,0)} \\ f_{(x,1)} \end{matrix} \right]$

于是上树的情况就是:在重链上维护这个转移式,因为一个点到根最多经过 logn 条重链,所以复杂度是 $O(nlog^2n)$

上树的时候会发现矩阵有一些变化,因为还要维护轻链上的转移,我们可以设 $A = \sum\limits_{v \in light_x} f_{(v,1)},B = v_x + \sum\limits_{v \in light_x} min(f_{(v,1)},f_{(v,0)})$

则每个点的矩阵是

$ \left[ \begin{matrix} A & \infty \\ B & B \end{matrix} \right]$

维护这个的同时维护一下 $g$ 数组表示这个点所有轻儿子的信息即可

写了好几次动态 dp 了,每次都重学

这是最后一次(flag

#include <bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
    int x = 0,f = 1; char ch = getchar();
    for(; !isdigit(ch); ch = getchar())if(ch == '-') f = -f;
    for(; isdigit(ch); ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const LL oo = 1e10, maxn = 5e5 + 10;
/*
A inf
B B

A = sigma (light, 1)
B = val + sigma(light, min(0, 1))

A inf   hv     (0)
B B     hv     (1)
*/
struct Matrix {
    LL a[2][2];
    Matrix(){ rep(i, 0, 1) rep(j, 0, 1) a[i][j] = oo; }
    Matrix(LL x, LL y){ a[0][1] = x, a[1][0] = a[1][1] = y, a[0][0] = oo; }
    Matrix operator * (const Matrix &b) const {
        Matrix c;
        rep(i, 0, 1) rep(j, 0, 1) rep(k, 0, 1) c.a[i][j] = min(c.a[i][j], a[i][k] + b.a[k][j]);
        return c;
    }
};

Matrix seg[maxn << 2], Mod;
#define ls (x << 1)
#define rs ((x << 1) | 1)
inline void update(int x, int l, int r, int pos, Matrix Mod) {
    //cout << x << endl;
    if(l == r) { seg[x] = Mod; return; }
    int mid = (l + r) >> 1;
    if(pos <= mid) update(ls, l, mid, pos, Mod);
    else update(rs, mid+1, r, pos, Mod);
    seg[x] = seg[ls] * seg[rs];
}
inline Matrix query(int x, int l, int r, int L, int R) {
    if(L <= l && r <= R) return seg[x];
    int mid = (l + r) >> 1; Matrix ret;
    ret.a[0][1] = ret.a[1][0] = oo; ret.a[0][0] = ret.a[1][1] = 0;
    if(L <= mid) ret = ret * query(ls, l, mid, L, R);
    if(R > mid) ret = ret * query(rs, mid+1, r, L, R);
    return ret;
}

int n, m, a[maxn]; LL f[maxn][2], g[maxn][2];
vector<int> G[maxn];
int fa[maxn], mxs[maxn], bl[maxn], pos[maxn], size[maxn], bot[maxn], dfn;
inline void dfs1(int x) {
    size[x] = 1; f[x][1] = a[x];
    for(auto to : G[x]) {
        if(to == fa[x]) continue;
        fa[to] = x;
        dfs1(to); size[x] += size[to];
        if(!mxs[x] || size[to] > size[mxs[x]]) mxs[x] = to;
        f[x][0] += f[to][1]; f[x][1] += min(f[to][0], f[to][1]);
    } //cout << x << " : " << mxs[x] << endl;
}
inline void dfs2(int x, int col) {
    bl[x] = col; pos[x] = ++dfn; g[x][1] = a[x];
    //cout << pos[x] << " " << bl[x] << endl;
    if(!mxs[x]) {
        update(1, 1, n, pos[x], Matrix(g[x][0], g[x][1]));
        bot[col] = dfn;
        return;
    } dfs2(mxs[x], col);
    for(auto to : G[x]) if(to != mxs[x] && to != fa[x]) {
        g[x][0] += f[to][1];
        g[x][1] += min(f[to][1], f[to][0]);
        dfs2(to, to);
    }
    update(1, 1, n, pos[x], Matrix(g[x][0], g[x][1]));
}
inline LL Modify(int x) {
    update(1, 1, n, pos[x], Matrix(g[x][0], g[x][1])); x = bl[x];
    while(x > 1) {
        Matrix cur = query(1, 1, n, pos[x], bot[x]);
        g[fa[x]][0] -= f[x][1];
        g[fa[x]][1] -= min(f[x][0], f[x][1]);
        f[x][0] = cur.a[0][1], f[x][1] = cur.a[1][1];
        g[fa[x]][0] += f[x][1];
        g[fa[x]][1] += min(f[x][0], f[x][1]);
        int cp = fa[x];
        update(1, 1, n, pos[cp], Matrix(g[cp][0], g[cp][1]));
        x = bl[fa[x]];
    }
//    cout << bot[1] << endl;
    Matrix ans = query(1, 1, n, 1, bot[1]);
//    cout << "COMP" << endl;
    return min(ans.a[0][1], ans.a[1][1]);
}
int main() {
    //freopen("defense.in","r",stdin);
    //freopen("defense.out","w",stdout);
    n = read(), m = read(); scanf("%*s");
    rep(i, 1, n) a[i] = read();
    rep(i, 2, n) {
        int u = read(), v = read();
        G[u].push_back(v); G[v].push_back(u);
    } dfs1(1); dfs2(1, 1);
    while(m--) {
        int a = read(), x = 1 ^ read(), b = read(), y = 1 ^ read();
        LL tmp1 = g[a][x], tmp2 = g[b][y];
        g[a][x] = oo, Modify(a);
        g[b][y] = oo; LL ans = Modify(b);
        if(ans >= oo) cout << -1 << '\n';
        else cout << ans << '\n';
        g[a][x] = tmp1, Modify(a);
        g[b][y] = tmp2, Modify(b);
    }
}
View Code

 

posted @ 2019-04-18 17:27  探险家Mr.H  阅读(343)  评论(0编辑  收藏  举报