HDU 6638 Snowy Smile(线段树最大子段和)题解

题意:

给一些坐标,问用一个任意大小矩形去框这些点,能获得的最大权值。\(n<=2000\)

思路:

先离散化,得到一张\(n*n\)的图,然后求最大子矩阵和。因为有权值的点只有\(n\)个,我们可以按\(x\)排序,然后枚举\(x\)的上界,每次只放出\(x\)相同的一层的点,用线段树维护最大子段和,复杂度\(O(nlog^2n)\)。交G++。

代码:

#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<stack>
#include<ctime>
#include<vector>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>
typedef long long ll;
using namespace std;
const int maxn = 2000 + 5;
const ll MOD = 998244353;
const int INF = 0x3f3f3f3f;
vector<int> yy;
struct Node{
    int v;
    int x, y;
    bool operator < (const Node &c) const{
        return x < c.x;
    }
}p[maxn];
ll Lmax[maxn << 2], Rmax[maxn << 2], Mmax[maxn << 2], sum[maxn << 2];
void push_up(int rt){
    Lmax[rt] = max(Lmax[rt << 1], sum[rt << 1] + Lmax[rt << 1 | 1]);
    Rmax[rt] = max(Rmax[rt << 1 | 1], sum[rt << 1 | 1] + Rmax[rt << 1]);
    Mmax[rt] = max(max(Mmax[rt << 1], Mmax[rt << 1 | 1]), Rmax[rt << 1] + Lmax[rt << 1 | 1]);
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void build(int l, int r, int rt){
    if(l == r){
        Mmax[rt] = Rmax[rt] = Lmax[rt] = sum[rt] = 0;
        return;
    }
    int m = (l + r) >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    push_up(rt);
}
void update(int pos, int l, int r, ll v, int rt){
    if(l == r){
        Mmax[rt] += v;
        Rmax[rt] += v;
        Lmax[rt] += v;
        sum[rt] += v;
        return;
    }
    int m = (l + r) >> 1;
    if(pos <= m)
        update(pos, l, m, v, rt << 1);
    else
        update(pos, m + 1, r, v, rt << 1 | 1);
    push_up(rt);
}
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        yy.clear();
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].v);
            yy.push_back(p[i].y);
        }
        sort(yy.begin(), yy.end());
        yy.erase(unique(yy.begin(), yy.end()), yy.end());
        for(int i = 1; i <= n; i++){
            p[i].y = lower_bound(yy.begin(), yy.end(), p[i].y) - yy.begin() + 1;
        }
        sort(p + 1, p + n + 1);

        ll ans = 0;
        for(int i = 1; i <= n; i++){    //x >= i
            if(i > 1 && p[i].x == p[i - 1].x) continue;
            build(1, yy.size(), 1);
            for(int j = i; j <= n; j++){
                update(p[j].y, 1, yy.size(), p[j].v, 1);
                if(p[j].x != p[j + 1].x || j == n) ans = max(ans, Mmax[1]);
            }
        }
        printf("%lld\n", ans);

    }
    return 0;
}


posted @ 2019-08-08 10:20  KirinSB  阅读(180)  评论(0)    收藏  举报