某岛

… : "…アッカリ~ン . .. . " .. .
June 25, 2023

CodeTON Round 5

Problem E. Tenzing and Triangle

只要能写出暴力 dp 就成功了 90% 啦!

不妨先把所有点都加起来,考虑最优能通过覆盖节省多少。我们发现一个有用的性质是,三角形覆盖的区域,是不需要重叠的,因此似乎可以简单的 1D/1D 动态规划。

这里我们用树状数组,可以维护出三角形覆盖区域的代价。

#include <lastweapon/io>
#include <lastweapon/fenwicktree>
using namespace lastweapon;

const int N = int(2e5) + 9;
int n, k, A; vector<PII> P[N]; LL f[N];

int main() {

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout);
#endif


	RD(n,k,A); LL z = 0;
	REP(i ,n) {
	    int x, y, c; RD(x, y, c);
	    z += c; P[k-x].PB({y, c});
	}

	fenwick_tree<int> T(k+1);

	REP(i, k+1) {
        for (auto p: P[i]) T.add(p.fi, p.se);
        checkMax(f[i], (LL)T.sum(0, i+1) - A*i);
        REP(j, i) checkMax(f[i], f[j] + T.sum(j+1, i+1) - A*(i-j-1));
	}

	cout << z - f[k] << endl;
}

进一步的我们再把这个转移分离分离放到线段树里求 rmq 就好了。

#include <lastweapon/io>
using namespace lastweapon;

const int N = int(2e5) + 9;
const int NN = 4*N;
int n, k, A; vector<PII> P[N]; int f[N];

struct SegTree {
#define lx (x<<1)
#define rx (lx|1)
#define ml ((l+r)>>1)
#define mr (ml+1)
#define lc lx,l,ml
#define rc rx,mr,r
#define rt 1,0,k

    int T[NN], D[NN];

    void add(int x, int d) {
        D[x] += d;
        T[x] += d;
    }
    void rls(int x) {
        //return;
        if (D[x]) {
            add(lx, D[x]);
            add(rx, D[x]);
            D[x] = 0;
        }
    }
    void upd(int x) {
        T[x] = max(T[lx], T[rx]);
    }
    void Build(int x, int l, int r) {
        if (l == r) {
            T[x] = A*l;
        } else {
            Build(lc);
            Build(rc);
            upd(x);
        }
    }

    int Add(int x, int l, int r, const int p, const int d) {
        if (l == r) {
            T[x] += d;
        } else {
            rls(x);
            if (p < mr) Add(lc, p, d);
            else Add(rc, p, d);
            upd(x);
        }
    }

    void Add(int x, int l, int r, const int a, const int b, const int d) {
        if (b < l || r < a) return;
        if (a <= l && r <= b) {
            add(x, d);
        } else {
            rls(x);
            Add(lc, a, b, d);
            Add(rc, a, b, d);
            upd(x);
        }
    }

    int Query(int x, int l, int r, const int a, const int b) {
        if (b < l || r < a) return 0;
        if (a <= l && r <= b) {
            return T[x];
        } else {
            rls(x);
            return max(Query(lc, a, b), Query(rc, a, b));
        }
    }
} T;

int main() {

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout);
#endif


	RD(n,k,A); int z = 0; REP(i, n) {
	    int x, y, c; RD(x, y, c); z += c;
	    P[k-x].PB({y, c});
	}

	T.Build(rt);

	REP(i, k+1) {
	    if (i) T.Add(rt, i, f[i-1]);
        for (auto p: P[i]) T.Add(rt, 0, p.fi, p.se);
        checkMax(f[i], T.Query(rt, 0, i) - A*i);
	}

	cout << z - f[k] << endl;
}