洛谷 P1502 窗口的星星
给定一个矩形(宽\(W\),高\(H\))和若干个点的坐标,求这个矩形能框住的点的权值和最大为多少。
把矩形右上角的点设为\(D\),对于某个点\(u\),当且仅当\(D\)在\((x_u, y_u)\)和\((x_u + W - 1, y_u + H - 1)\)所构成的矩形中时,点\(u\)才能被框住
问题就转换为了,给定若干个矩形和对应的权值,问哪个坐标的权值和最大。可以用扫描线解决
线段树维护坐标轴上的区间最大值(我用的\(y\)轴),把所有线段按\(x\)排序,碰到入边就加上对应权值,碰到出边就减去,要用懒标记
易错点:
1、如果横坐标相等,入边在前,都是入边,权值大的在前(否则不是最优)
2、因为线段树的结点是单位长度的线段,而本题端点可以重合,所以右端点要\(+1\)
举个例子:有两个入边\((0, 3)\)和\((3, 4)\),不处理右端点的话\((0, 1), (1, 2), (2, 3), (3, 4)\)各加了一次,但是其实\(3\)这个点要加两次
#include<bits/stdc++.h>
using namespace std;
#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;
const int INF = 0X3f3f3f3f, N = 1e4 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);
int n, W, H;
int cnt;
struct NODE {
int l, r;
LL val, mx, lazy;
}tr[N * 8];
struct Segment {
int x, y1, y2;
int w, tg;
bool operator < (const Segment &t) const {
if (x == t.x) {
if (tg + t.tg == 0) return tg > t.tg;
return w > t.w;
}
return x < t.x;
}
}seg[N << 1];
vector<int> ys;
int find (int x) {
return lower_bound(ys.begin(), ys.end(), x) - ys.begin();
}
void push_up(int u) {
tr[u].mx = max(tr[u << 1].mx, tr[u << 1 | 1].mx);
}
void push_down(int u) {
int lson = u << 1, rson = u << 1 | 1;
tr[lson].mx += tr[u].lazy, tr[rson].mx += tr[u].lazy;
tr[lson].lazy += tr[u].lazy, tr[rson].lazy += tr[u].lazy;
tr[u].lazy = 0;
}
void build(int u, int l, int r) {
tr[u] = {l, r, 0, 0, 0};
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void modify(int u, int L, int R, int d) {
if (L <= tr[u].l && R >= tr[u].r) tr[u].mx += d, tr[u].lazy += d;
else {
push_down(u);
int mid = tr[u].l + tr[u].r >> 1;
if (L <= mid) modify(u << 1, L, R, d);
if (R > mid) modify(u << 1 | 1, L, R, d);
push_up(u);
}
}
LL query(int u, int L, int R) {
if (L <= tr[u].l && R >= tr[u].r) return tr[u].mx;
else {
push_down(u);
int mid = tr[u].l + tr[u].r >> 1;
LL mx1 = 0, mx2 = 0;
if (L <= mid) mx1 = query(u << 1, L, R);
if (R > mid) mx2 = query(u << 1 | 1, L, R);
push_up(u);
return max(mx1, mx2);
}
}
void print_tree(int u, int l, int r) {
cout << "u: " << u << " l: " << tr[u].l << " r: " << tr[u].r << " mx :" << tr[u].mx << endl;
if (l == r) return;
int mid = l + r >> 1;
print_tree(u << 1, l, mid), print_tree(u << 1 | 1, mid + 1, r);
}
void work() {
cnt = 0, ys.clear();
cin >> n >> W >> H;
W--, H--;
rep (i, 1, n) {
int x, y, w;
cin >> x >> y >> w;
seg[++cnt] = {x, y, y + H, w, 1};
seg[++cnt] = {x + W, y, y + H, w, -1};
ys.push_back(y), ys.push_back(y + H);
}
sort(seg + 1, seg + cnt + 1);
sort(ys.begin(), ys.end());
ys.erase(unique(ys.begin(), ys.end()), ys.end());
build(1, 0, ys.size() - 2);
LL res = 0;
rep (i, 1, cnt) {
modify(1, find(seg[i].y1), find(seg[i].y2), seg[i].tg * seg[i].w);
res = max(res, query(1, 0, ys.size() - 2));
}
cout << res << endl;
}
signed main() {
IO
int test = 1;
cin >> test;
while (test--) {
work();
}
return 0;
}