[線段樹分治][DP] LOJ #534. 「LibreOJ Round #6」花團

Solution

操作相當於是動態的做一個揹包DP。
離線的話,線段樹分治一下。
因爲結尾是已知的,可以一邊分治,得到一個修改操作,就插到線段樹。
只要保證分治從左到右,每個操作都在線段樹上得到了實現。
1.5×104 可以跑O(n2logn) 瞭解一下。
實際上跑不到這麼滿????

#include <bits/stdc++.h>
#define show(x) cerr << #x << " = " << x << endl
using namespace std;
typedef long long ll;
typedef pair<int, int> pairs;

const int N = 15151;

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

int n, m, q, tp;
int opt, x, y, z, d, last;
int f[20][N];
vector<pairs> node[N << 2];

inline void dp(int *f, int v, int w) {
    for (int i = m - v; ~i; i--)
        f[i + v] = max(f[i + v], f[i] + w);
}
inline void add(int o, int l, int r, int L, int R, int v, int w) {
    if (l >= L && r <= R)
        return (void)(node[o].push_back(pairs(v, w)));
    int mid = (l + r) >> 1;
    if (L <= mid) add(o << 1, l, mid, L, R, v, w);
    if (R > mid) add(o << 1 | 1, mid + 1, r, L, R, v, w);
}
inline void divAndConq(int o, int l, int r, int dep) {
    int *g = f[dep];
    for (auto u: node[o])
        dp(g, u.first, u.second);
    if (l == r) {
        read(opt);
        if (opt == 1) {
            read(x); read(y); read(z);
            d = last * tp;
            x -= d; y -= d; z -= d;
            if (l != z)
                add(1, 1, n, l + 1, z, x, y);
        } else {
            read(x);
            x -= last * tp;
            if (g[x] < 0) {
                printf("0 0\n");
                last = 0;
            } else {
                printf("1 %d\n", g[x]);
                last = 1 ^ g[x];
            }
        }
        return;
    }
    int mid = (l + r) >> 1;
    for (int i = 0; i <= m; i++) f[dep + 1][i] = g[i];
    divAndConq(o << 1, l, mid, dep + 1);
    for (int i = 0; i <= m; i++) f[dep + 1][i] = g[i];
    divAndConq(o << 1 | 1, mid + 1, r, dep + 1);
}

int main(void) {
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
    read(n); read(m); read(tp);
    for (int i = 1; i <= m; i++)
        f[0][i] = -1 << 30;
    divAndConq(1, 1, n, 0);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章