杭电多校第六场 E Snowy Smile (线段树维护二维最大子段和)

题目链接

题解:

枚举上下边界,用线段树维护区间最大子段和。

具体的,首先枚举下界,固定下界的情况下,上界的枚举与计算答案并更新可以 O(n) 完成。

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
#define int ll
#define PI acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<int, int>
#define fastio ios::sync_with_stdio(false), cin.tie(0)
const int mod = 998244353;
const int M = 1000000 + 10;
const int N = 2000 + 10;

int t, n;
int ma[N<<2], lma[N<<2], rma[N<<2], sum[N<<2];
struct node {
    int x, y, w;
    bool operator < (const node &cmp) const {
        return y < cmp.y;
    }
} no[N];
int cpx[N], cntx, cpy[N], cnty;

void build(int l = 1, int r = cntx, int rt = 1)
{
    ma[rt] = lma[rt] = rma[rt] = sum[rt] = 0;
    if(l == r) return ;

    int mid = (l + r) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);

}

void add(int pos, int val, int l = 1, int r = cntx, int rt = 1)
{
    if(l == r) {
        sum[rt] += val;
        ma[rt] += val;
        lma[rt] += val;
        rma[rt] += val;
        return ;
    }

    int mid = (l + r) >> 1;
    if(pos <= mid) add(pos, val, l, mid, rt << 1);
    else add(pos, val, mid + 1, r, rt << 1 | 1);

    lma[rt] = max(lma[rt << 1], sum[rt << 1] + lma[rt << 1 | 1]);
    rma[rt] = max(rma[rt << 1 | 1], sum[rt << 1 | 1] + rma[rt << 1]);
    ma[rt] = max(max(ma[rt << 1], ma[rt << 1 | 1]), rma[rt << 1] + lma[rt << 1 | 1]);
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}

signed main()
{
    fastio;
    cin >> t;
    while(t --) {
        cin >> n;
        for(int i = 1; i <= n; i ++) {
            cin >> no[i].x >> no[i].y >> no[i].w;
            cpx[i] = no[i].x, cpy[i] = no[i].y;
        }

        sort(cpx + 1, cpx + 1 + n);
        cntx = unique(cpx + 1, cpx + 1 + n) - cpx - 1;
        sort(cpy + 1, cpy + 1 + n);
        cnty = unique(cpy + 1, cpy + 1 + n) - cpy - 1;

        for(int i = 1; i <= n; i ++) {
            no[i].x = lower_bound(cpx + 1, cpx + 1 + cntx, no[i].x) - cpx;
            no[i].y = lower_bound(cpy + 1, cpy + 1 + cnty, no[i].y) - cpy;
        }

        sort(no + 1, no + 1 + n);

        int ans = 0;
        for(int i = 1; i <= cnty; i ++) {
            build();
            int now = 1;
            while(now <= n && no[now].y < i) now ++;
            for(int j = i; j <= cnty; j ++) {
                while(now <= n && no[now].y == j) {
                    add(no[now].x, no[now].w);
                    now ++;
                }
                ans = max(ans, ma[1]);
            }
        }
        cout << ans << endl;
    }
    return 0;
}

/*

  Rejoicing in hope, patient in tribulation.

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值