2019HDU多校第6场 1005.Snowy Smile(线段树维护子段和)

给出若干个带权点,问丢一个任意大小的矩形下去框柱一些点,最多能得到多少权值。

补题。

n总和小于1e4,给了4秒,大致是一个n方log的算法。

枚举矩阵的上下(或左右)两条边界,剩下两条边并不一定要枚举出来,可以用一个线段树维护最大子段和直接搞定。

板子+1?

#include

using namespace std;

typedef long long ll;
const int maxn = 2e3 + 5;

struct node {
    int x, y;
    ll w;
} p[maxn];

int _, n;

vector<int> G[maxn];
vector<int> X, Y;

struct segmentTree {
    // -ai(ls) + aj(rs) ←前缀和(i < j)
    ll s[maxn << 2], ls[maxn << 2], rs[maxn << 2], lrs[maxn << 2];

    void pushUp(int rt) {
        s[rt] = s[rt << 1] + s[rt << 1 | 1];
        ls[rt] = max(ls[rt << 1], s[rt << 1] + ls[rt << 1 | 1]);
        rs[rt] = max(rs[rt << 1 | 1], s[rt << 1 | 1] + rs[rt << 1]);
        lrs[rt] = max(max(lrs[rt << 1], lrs[rt << 1 | 1]), rs[rt << 1] + ls[rt << 1 | 1]);
    }

    void build(int rt, int l, int r) {
        s[rt] = ls[rt] = rs[rt] = lrs[rt] = 0;
        if (l == r) {
            return;
        }
        int mid = (l + r) >> 1;
        build(rt << 1, l, mid);
        build(rt << 1 | 1, mid + 1, r);
    }

    void update(int rt, int l, int r, int pos, ll val) {
        if (l == r) {
            s[rt] += val;
            ls[rt] = rs[rt] = lrs[rt] = max(0LL, s[rt]);
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            update(rt << 1, l, mid, pos, val);
        } else {
            update(rt << 1 | 1, mid + 1, r, pos, val);
        }
        pushUp(rt);
    }

    void solve() {
        ll ans = 0;
        for (int i = 1; i <= X.size(); ++i) {
            build(1, 1, Y.size());
            for (int j = i; j <= X.size(); ++j) {
                for (auto e : G[j]) {
                    update(1, 1, Y.size(), p[e].y, p[e].w);
                }
                ans = max(ans, lrs[1]);
            }
        }
        printf("%lld\n", ans);
    }
} st;

int main() {
    scanf("%d", &_);
    while (_--) {
        scanf("%d", &n);
        X.clear(), Y.clear();
//        X.push_back(INT_MIN), Y.push_back(INT_MIN);
        for (int i = 1; i <= n; ++i) {
            scanf("%d%d%lld", &p[i].x, &p[i].y, &p[i].w);
            X.push_back(p[i].x);
            Y.push_back(p[i].y);
        }
        sort(X.begin(), X.end());
        X.erase(unique(X.begin(), X.end()), X.end());
        sort(Y.begin(), Y.end());
        Y.erase(unique(Y.begin(), Y.end()), Y.end());

        for (int i = 0; i <= X.size(); ++i) {
            G[i].clear();
        }

        for (int i = 1; i <= n; ++i) {
            p[i].x = lower_bound(X.begin(), X.end(), p[i].x) - X.begin() + 1;
            p[i].y = lower_bound(Y.begin(), Y.end(), p[i].y) - Y.begin() + 1;
            G[p[i].x].push_back(i);
        }

        st.solve();
    }
    return 0;
}

你可能感兴趣的:(ACM)