[NOIP2018]保卫王国(ddp)

本题博主用的是ddp写法,如果想学倍增的话请退回去。

Solution

这道题如果用ddp的话就是道模板题了吧。

必须选看成把权值赋为负无穷,不选看成把权值赋为无穷,如果最后答案大于无穷或小于负无穷即无解。

最后要复原。

Code(重链剖分+线段树)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
typedef long long ll;
const int N = 100010;
const ll inf = 0x3f3f3f3f3f3f3f3f;
namespace IO{
    template <typename T> void read(T &x) {
        T f = 1;
        char ch = getchar();
        for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
        for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
        x *= f;
    }
    template <typename T> void write(T x) {
        if (x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
    template <typename T> void print(T x) {
        if (x < 0) putchar('-'), x = -x;
        write(x);
        putchar('
');
    }
}using namespace IO;

int n, m;
ll p[N];
char s[10];

namespace QXX{
    struct node{
        int pre, to;
    }edge[N << 1];
    int head[N], tot;
    inline void add(int u, int v) {
        edge[++tot] = node{head[u], v};
        head[u] = tot;
    }
}using namespace QXX;

namespace MATRIX{
    template <typename T> void cmin(T &x, T y) {if (y < x) x = y;}
    template <typename T> void cmax(T &x, T y) {if (y > x) x = y;}
    struct Matrix{
        ll arr[3][3];
    };
    inline void init(Matrix &X) {
        memset(X.arr, 0x3f, sizeof(X.arr));
    }
    inline Matrix Mul(Matrix X, Matrix Y) {
        Matrix Z;
        init(Z);
        for (int i = 1; i <= 2; i++)
            for (int j = 1; j <= 2; j++)
                for (int k = 1; k <= 2; k++)
                    cmin(Z.arr[i][j], X.arr[i][k] + Y.arr[k][j]);
        return Z;
    }
}using namespace MATRIX;

namespace TCP{
    Matrix A[N];
    ll dp[N][2];
    int dfn[N], pos[N], top[N], End[N], num;
    int sz[N], fa[N], son[N];
    void dfs1(int x) {
        sz[x] = 1;
        for (int i = head[x]; i; i = edge[i].pre) {
            if (edge[i].to == fa[x]) continue;
            fa[edge[i].to] = x;
            dfs1(edge[i].to);
            sz[x] += sz[edge[i].to];
            if (sz[edge[i].to] > sz[son[x]]) son[x] = edge[i].to;
        }
    }
    void dfs2(int x, int chain) {
        dfn[x] = ++num, top[x] = chain, pos[dfn[x]] = x;
        init(A[x]);
        A[x].arr[1][1] = A[x].arr[1][2] = p[x];
        A[x].arr[2][1] = 0;
        if (son[x])
            dfs2(son[x], chain), dp[x][0] = dp[son[x]][1], dp[x][1] = min(dp[son[x]][0], dp[son[x]][1]);
        else
            End[chain] = dfn[x];
        for (int i = head[x]; i; i = edge[i].pre) {
            if (edge[i].to == fa[x] || edge[i].to == son[x]) continue;
            dfs2(edge[i].to, edge[i].to);
            A[x].arr[2][1] += dp[edge[i].to][1];
            A[x].arr[1][1] += min(dp[edge[i].to][1], dp[edge[i].to][0]);
            A[x].arr[1][2] = A[x].arr[1][1];
        }
        dp[x][0] += A[x].arr[2][1];
        dp[x][1] += A[x].arr[1][1];
    }
}using namespace TCP;

namespace Segment_Tree{
    struct Segment{
        Matrix val;
    }tr[N << 2];
    inline void push_up(int p) {tr[p].val = Mul(tr[p << 1].val, tr[p << 1 | 1].val);}
    void build(int p, int l, int r) {
        if (l == r) {
            tr[p].val = A[pos[l]];
            return;
        }
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        push_up(p);
    }
    void change(int p, int l, int r, int Pos) {
        if (l == r) {
            tr[p].val = A[pos[l]];
            return;
        }
        int mid = (l + r) >> 1;
        if (Pos <= mid) change(p << 1, l, mid, Pos);
        else change(p << 1 | 1, mid + 1, r, Pos);
        push_up(p);
    }
    Matrix query(int p, int l, int r, int x, int y) {
        if (x <= l && r <= y) return tr[p].val;
        int mid = (l + r) >> 1;
        if (y <= mid) return query(p << 1, l, mid, x, y);
        else if (x > mid) return query(p << 1 | 1, mid + 1, r, x, y);
        else return Mul(query(p << 1, l, mid, x, mid), query(p << 1 | 1, mid + 1, r, mid + 1, y));
    }
}using namespace Segment_Tree;

inline void update(int a, ll b) {//将节点 a 的权值改为 b 
    A[a].arr[1][1] += b - p[a];
    A[a].arr[1][2] = A[a].arr[1][1];
    p[a] = b;
    while (a) {
        Matrix bef = query(1, 1, n, dfn[top[a]], End[top[a]]);
        change(1, 1, n, dfn[a]);
        Matrix aft = query(1, 1, n, dfn[top[a]], End[top[a]]);
        a = fa[top[a]];
        A[a].arr[1][1] += min(aft.arr[1][1], aft.arr[2][1]) - min(bef.arr[1][1], bef.arr[2][1]);
        A[a].arr[1][2] = A[a].arr[1][1];
        A[a].arr[2][1] += aft.arr[1][1] - bef.arr[1][1];
    }
}

int main() {
    read(n); read(m); scanf("%s", s + 1);
    for (int i = 1; i <= n; i++) read(p[i]);
    for (int i = 1, u, v; i < n; i++) read(u), read(v), add(u, v), add(v, u);
    dfs1(1);
    dfs2(1, 1);
    build(1, 1, n);
    while (m--) {
        int a, x, b, y;
        read(a); read(x); read(b); read(y);
        ll out = 0, tmpa = p[a], tmpb = p[b];
        if (x == 0) update(a, inf);
        else update(a, -inf), out += inf + tmpa;
        if (y == 0) update(b, inf);
        else update(b, -inf), out += inf + tmpb;
        Matrix ans = query(1, 1, n, dfn[top[1]], End[top[1]]);
        out += min(ans.arr[1][1], ans.arr[2][1]);
        if (-inf < out && out < inf) print(out);
        else print(-1);
        update(a, tmpa);
        update(b, tmpb);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zcr-blog/p/13102160.html