题意: 给出平面上n个点
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi),每个点都有一个权值
w
i
(
−
1
0
9
<
x
i
,
y
i
,
w
i
<
1
0
9
)
w_i(-10^9<x_i,y_i,w_i<10^9)
wi(−109<xi,yi,wi<109),选取一个边与坐标轴平行的矩形,使这个矩形内的点的权值之和最大,问这个最大权值和是多少。
思路: 线段树维护区间最大子段和。学会线段树维护区间最大子段和后对这些点的
x
,
y
x,y
x,y坐标离散化,对
x
x
x坐标排序,然后暴力循环遍历
[
x
m
i
n
,
x
m
a
x
]
[x_{min},x_{max}]
[xmin,xmax]的最大子段和,复杂度
n
2
l
o
g
n
n^2log n
n2logn。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e3 + 10;
int t, n;
struct node {
int x, y;
ll w;
bool operator <(const node &a)const {
return x < a.x;
}
} no[N];
struct segment_tree {
ll sum;//[l,r]区间之和
ll msum;//[l,r]内的最大子段和
ll mpre;//[l,r]内的最大前缀和
ll mpost;//[l,r]内的最大后缀和
} tree[N << 2];
void pushup(int rt) {
int ls = rt << 1, rs = rt << 1 | 1;
//区间之和 = 左区间之和+右区间之和
tree[rt].sum = tree[ls].sum + tree[rs].sum;
//区间最大子段和 = max(左区间最大子段和,右区间最大子段和,左区间最大后缀和+右区间最大前缀和)
tree[rt].msum = max(max(tree[ls].msum, tree[rs].msum), tree[ls].mpost + tree[rs].mpre);
//区间最大前缀和 = max(左区间最大前缀和,左区间之和+右区间最大前缀和)
tree[rt].mpre = max(tree[ls].mpre, tree[rs].mpre + tree[ls].sum);
//区间最大后缀和 = max(右区间最大后缀和,右区间之和+左区间最大后缀和)
tree[rt].mpost = max(tree[rs].mpost, tree[ls].mpost + tree[rs].sum);
}
void update(int pos, int v, int l, int r, int rt) {
if(l == r) {
tree[rt].sum += v;
tree[rt].msum += v;
tree[rt].mpre += v;
tree[rt].mpost += v;
return;
}
int m = (l + r) >> 1;
if(pos <= m)
update(pos, v, l, m, rt << 1);
else
update(pos, v, m + 1, r, rt << 1 | 1);
pushup(rt);
}
void build(int l, int r, int rt) {
tree[rt].sum = tree[rt].msum = tree[rt].mpre = tree[rt].mpost = 0;
if(l == r)
return;
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
}
int main() {
scanf("%d", &t);
while(t--) {
vector<int> v;
vector<int> vs;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d%d%d", &no[i].x, &no[i].y, &no[i].w);
v.push_back(no[i].y);
vs.push_back(no[i].x);
}
sort(v.begin(), v.end()), v.erase(unique(v.begin(), v.end()), v.end());
sort(vs.begin(), vs.end()), vs.erase(unique(vs.begin(), vs.end()), vs.end());
int ny = v.size();
int nx = vs.size();
for(int i = 1; i <= n; i++) {
no[i].y = lower_bound(v.begin(), v.end(), no[i].y) - v.begin() + 1;
no[i].x = lower_bound(vs.begin(), vs.end(), no[i].x) - vs.begin() + 1;
}
sort(no + 1, no + n + 1);
ll ans = 0;
int now = 1;
for(int i = 1; i <= nx; i++) {
build(1, ny, 1);
for(int j = i, k = now; j <= nx; j++) {
while(k <= n && no[k].x == j) {
update(no[k].y, no[k].w, 1, ny, 1);
k++;
}
if(j == i)
now = k;
ans = max(ans, tree[1].msum);
}
}
printf("%lld\n", ans);
}
return 0;
}