洛谷 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;
}
posted @ 2022-09-18 21:41  xhy666  阅读(35)  评论(0)    收藏  举报