POJ2482 Stars in Your Window - 平面扫描 - 坐标离散化 - 区间更新的线段树

Stars in Your Window

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 15614   Accepted: 4210

Description

Here comes the problem: Assume the sky is a flat plane. All the stars lie on it with a location (x, y). for each star, there is a grade ranging from 1 to 100, representing its brightness, where 100 is the brightest and 1 is the weakest. The window is a rectangle whose edges are parallel to the x-axis or y-axis. Your task is to tell where I should put the window in order to maximize the sum of the brightness of the stars within the window. Note, the stars which are right on the edge of the window does not count. The window can be translated but rotation is not allowed.
题目贴图

Input

There are several test cases in the input. The first line of each case contains 3 integers: n, W, H, indicating the number of stars, the horizontal length and the vertical height of the rectangle-shaped window. Then n lines follow, with 3 integers each: x, y, c, telling the location (x, y) and the brightness of each star. No two stars are on the same point.

There are at least 1 and at most 10000 stars in the sky. 1<=W,H<=1000000, 0<=x,y<2^31.

Output

For each test case, output the maximum brightness in a single line.

Sample Input

3 5 4
1 2 3
2 3 2
6 3 1
3 5 4
1 2 3
2 3 2
5 3 1

Sample Output

5
6

 
 

题目大概意思:

平面上给出 n ( 1 n 1 0 4 ) n(1≤n≤10^4) 个点,第 i i 个点的坐标是 ( x i , y i ) (x_i,y_i) ,价值为 c i c_i ,使用 x x 轴方向上长度为 W W y y 轴方向上长度 H H 的矩形覆盖点,矩形可以任意平移,但不能旋转。求矩形能覆盖的点的权值之和的最大值。

其中 x i , y i x_i,y_i 均为整数且 0 x i , y i &lt; 2 31 0≤x_i,y_i&lt;2^{31} .

 
 

分析:

用一条垂直于 x x 轴的直线按 x x 坐标从小到大扫描,设扫描线当前的 x x 坐标为 x c x_c .

设一个抽象的数组 S S ,令 S [ y s ] S[y_s] 表示点集 { p &ThinSpace; &ThinSpace; x c W &lt; p . x x c &ThinSpace; , &ThinSpace; y s H p . y &lt; y s } \{p\,|\,x_c-W&lt;p.x≤x_c\,,\,y_s-H≤p.y&lt;y_s\} 的权值之和,即扫描线每扫描过某个点 p p 则在数组 S S 的区间 [ p . y , p . y + H ) [p.y,p.y+H) 上加上点 p p 的权值,每当某个已扫描过的点 p p 与当前扫描线的距离大于等于 W W 了,则在数组 S S 的区间 [ p . y , p . y + H ) [p.y,p.y+H) 上减去自己的权值。每个点被扫描过且与扫描线距离小于 W W 才使其权值加在 S S 上意味着这些点可以被右边界的 x x 坐标等于当前扫描线的 x x 坐标 x c x_c 的矩形所覆盖到,而每个点更新的区间 [ p . y , p . y + H ) [p.y,p.y+H) 就意味着只有下边界位于 [ p . y , p . y + H ) [p.y,p.y+H) 的矩形才可以覆盖到该点。

那么每一时刻的扫描线与该时刻的 S S 数组确定了一系列右边界的 x x 坐标为 x c x_c 的矩形能够覆盖的点的权值,而此时刻的矩形能够覆盖的权值之和的最大值就是数组 S S 的最大值。

因此在扫描的过程中,我们需要一种高效的数据结构来维护扫描线上的数据(即抽象出的 S S 数组),我们需要的操作是对 S S 的区间修改与区间最大值的询问。因此我们只需使用区间更新的线段树来维护区间的最大值即可。而由于坐标范围很大,我们需要预先对坐标进行离散化处理。

另外,还需要警惕在计算 p . y + H p.y+H 时的溢出问题。

 
 
下面贴代码:

#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;

typedef long long ll;
const int MAX_N = 10005;

struct P
{
	int max;
	int d;
};

P dat[(1 << 15) + 5];
int _n;
inline const int _max(const int& a, const int& b);
void init(const int n);
void push_down(const int k);
void push_up(int k);
void update(const int& left, const int& right, const int& x, const int k, const int begin, const int end);
int query(const int& left, const int& right, const int k, const int begin, const int end);


struct Star
{
	int x;
	int y;
	int c;
	bool operator< (const Star& R)const
	{
		return x < R.x;
	}
}star[MAX_N];
int kx[MAX_N];
int ky[MAX_N];


int main()
{
	int n, W, H;

	while (~scanf("%d%d%d", &n, &W, &H))
	{
		int kxcnt = 0, kycnt = 0;
		for (int i = 0; i < n; i++)
		{
			Star& cur = star[i];
			scanf("%d%d%d", &cur.x, &cur.y, &cur.c);
			kx[kxcnt++] = cur.x;
			ky[kycnt++] = cur.y;
		}
		sort(star, star + n);
		sort(kx, kx + kxcnt);
		sort(ky, ky + kycnt);
		kxcnt = unique(kx, kx + kxcnt) - kx;
		kycnt = unique(ky, ky + kycnt) - ky;
		init(kycnt + 1);

		int lb = 0, ans = INT_MIN;
		for (int rb = 0; rb < n; rb++)
		{
			const Star& cur = star[rb];
			while (lb != rb && star[lb].x <= cur.x - W)
			{
				const Star& pre = star[lb++];
				update
				(
					lower_bound(ky, ky + kycnt, pre.y) - ky,
					upper_bound(ky, ky + kycnt, (ll)pre.y + H - 1) - ky - 1, // 转换为 ll 防止溢出
					-pre.c, 0, 0, _n
				);
			}
			update
			(
				lower_bound(ky, ky + kycnt, cur.y) - ky,
				upper_bound(ky, ky + kycnt, (ll)cur.y + H - 1) - ky - 1,     // 转换为 ll 防止溢出
				cur.c, 0, 0, _n
			);
			ans = _max(ans, query(0, _n, 0, 0, _n));
		}
		printf("%d\n", ans);
	}

	return 0;
}

inline const int _max(const int& a, const int& b)
{
	return a > b ? a : b;
}

void init(const int n)
{
	_n = 1;
	while (_n < n)
	{
		_n <<= 1;
	}
	--_n;
	memset(dat, 0, 2 * (_n + 1) * sizeof(dat[0]));
}

void push_down(const int k)
{
	P& cur = dat[k];
	if (cur.d)
	{
		P& ls = dat[(k << 1) + 1];
		P& rs = dat[(k << 1) + 2];
		ls.d += cur.d;
		rs.d += cur.d;
		ls.max += cur.d;
		rs.max += cur.d;
		cur.d = 0;
	}
}

void push_up(int k)
{
	while (k)
	{
		k = (k - 1) >> 1;
		dat[k].max = _max(dat[(k << 1) + 1].max, dat[(k << 1) + 2].max);
	}
}

void update(const int& left, const int& right, const int& x, const int k, const int begin, const int end)
{
	if (left <= begin && end <= right)
	{
		P& cur = dat[k];
		cur.d += x;
		cur.max += x;
		push_up(k);
	}
	else if (left <= end && begin <= right)
	{
		push_down(k);
		return update(left, right, x, (k << 1) + 1, begin, (begin + end) >> 1),
			update(left, right, x, (k << 1) + 2, ((begin + end) >> 1) + 1, end);
	}
}

int query(const int& left, const int& right, const int k, const int begin, const int end)
{
	if (left <= begin && end <= right)
	{
		return dat[k].max;
	}
	else if (left <= end && begin <= right)
	{
		push_down(k);
		return _max
		(
			query(left, right, (k << 1) + 1, begin, (begin + end) >> 1),
			query(left, right, (k << 1) + 2, ((begin + end) >> 1) + 1, end)
		);
	}
	else return INT_MIN;
}

原创文章 42 获赞 22 访问量 3033

猜你喜欢

转载自blog.csdn.net/weixin_44327262/article/details/98780772