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