小卡买到了一套新房子,他十分的高兴,在房间里转来转去。
晚上,小卡从阳台望出去,“哇~~~~好多星星啊”,但他还没给其他房间设一个窗户。
天真的小卡总是希望能够在晚上能看到最多最亮的星星,但是窗子的大小是固定的,边也必须和地面平行。
这时小卡使用了超能力(透视术)知道了墙后面每个星星的位置和亮度,但是小卡发动超能力后就很疲劳,只好拜托你告诉他最多能够有总和多亮的星星能出现在窗口上。
小卡买的窗户框是金属做的,所以在边框上的不算在内。
本题有多组数据,第一行为 T,表示有 T 组数据。
对于每组数据:
第一行 3 个整数 n,W,H,W, 表示有 n 颗星星,窗口宽为 W,高为 H。
接下来 n 行,每行三个整数 x i , y i , l i x_i,y_i,l_i xi,yi,li 表示星星的坐标在 ( x i , y i ) (x_i,y_i) (xi,yi)上,亮度为 l i l_i li
2
3 5 4
1 2 3
2 3 2
6 3 1
3 5 4
1 2 3
2 3 2
5 3 1
T 个整数,表示每组数据中窗口星星亮度总和的最大值。
5
6
对于每一个星星,包含这个星星的最优矩形有四种情况,即这个星星在矩形的边角处,这里可以取星星在左下角的情况, ( x i , y i ) (x_i,y_i) (xi,yi)对应一个 ( x i + W − 1 , y i + H − 1 ) (x_i+W-1,y_i+H-1) (xi+W−1,yi+H−1)的矩阵,最优解一定在这n个矩阵其中之一。
用线段树+扫描线处理这n个矩阵。
这里用对x轴用线段树,从下到上处理每条线。
我们将矩阵简化为区间,线段树维护区间的最大值
对于每个矩阵,记录上下两条边
struct line
{
int h, l, r, v;
bool operator <(const line& x)const
{
if(h!=x.h) return h < x.h;
return v > x.v;
}
};
line seg[maxn << 1];
h是这条边的高度
l,r是左右端点
v是这个矩阵对应的星星的亮度
对所有边从低到高排序,依次处理
因为边是从低到高依次处理,并且用线段树维护区间的最大值,那么可以将矩阵的下边的价值设为星星的亮度,矩阵上边的价值设为下边的相反数,这样就可以完成求矩阵最大价值的目的
处理边 s e g [ i ] seg[i] seg[i],给这个边对应的区间加这个边的价值。
每次处理完之后,线段树的根节点就是当前最优解。
离散化,每个星星对应的区间 ( x , x + W − 1 ) (x,x+W-1) (x,x+W−1),把所有区间端点记录一下,排序,去掉重复点就是线段树需要维护的区间范围。线段树的叶子节点是 ( x x i , x x i ) (xx_i,xx_i) (xxi,xxi),对每个边进行更改时,先要定位到左右端点的i,再更改i区间的值
unique函数可以直接去重
当处理进星星的有效范围时(y),会有一条下边会给区间加星星的价值
当处理出星星的有效范围时(y),会有一条上边会给区间减星星的价值
其实也是一种暴力,从下到上,很巧妙的遍历的所有可能性
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#pragma GCC optimize(2)
#pragma warning(disable:4996)
using namespace std;
const int maxn = 10001;
struct line
{
int h, l, r, v;
bool operator <(const line& x)const
{
if(h!=x.h) return h < x.h;
return v > x.v;
}
};
line seg[maxn << 1];
int xx[maxn << 1];
int maxv[maxn << 3], tag[maxn << 3];
void update_lower(int x,int l,int r)
{
if (tag[x] && l != r)
{
tag[x << 1] += tag[x];
maxv[x << 1] += tag[x];
tag[x << 1 | 1] += tag[x];
maxv[x << 1 | 1] += tag[x];
tag[x] = 0;
}
}
void change(int x, int l, int r, int ql, int qr, int k)
{
if (l >= ql && r <= qr)
{
maxv[x] += k;
tag[x] += k;
return;
}
update_lower(x, l, r);
int mid = (l + r) >> 1;
if (mid >= ql) change(x << 1, l, mid, ql, qr, k);
if (mid < qr) change(x << 1 | 1, mid + 1, r, ql, qr, k);
maxv[x] = max(maxv[x << 1], maxv[x << 1 | 1]);
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
int n, w, h; scanf("%d%d%d", &n, &w, &h);
int x, y, l;
memset(maxv, 0, sizeof(maxv));
memset(tag, 0, sizeof(tag));
for (int i = 1; i <= n; i++)
{
scanf("%d%d%d", &x,&y,&l);
seg[i] = { y,x,x + w - 1,l };
seg[i + n] = { y + h - 1,x,x + w - 1,-l };
xx[i] = x;
xx[i + n] = x + w - 1;
}
n = n << 1;
sort(seg + 1, seg + 1 + n);
sort(xx + 1, xx + 1 + n);
int cntx = unique(xx + 1, xx + 1 + n) - xx - 1;
int ans = 0;
for (int i = 1; i <= n; i++)
{
int L = lower_bound(xx + 1, xx + 1 + cntx, seg[i].l) - xx;
int R = lower_bound(xx + 1, xx + 1 + cntx, seg[i].r) - xx;
change(1, 1, cntx, L, R, seg[i].v);
ans = max(ans, maxv[1]);
}
cout << ans << '\n';
}
return 0;
}