POJ 2482 Stars in Your Window 线段树+扫描线

妈个鸡,要不是队友提醒,我能把题面上的那封情书读完,读了一半多了都

然后题意就是,在一个平面直角坐标系上,有一些点,每个点有一个权值,用一个矩形框去框住他们,问怎么才能使框住的所有点的权值和最大,边界上的点不算。

边界上的点 不算,我之前只做到过一次边界上的点算的啊,怎么办,把长和宽都各自-1就好啦。处理之后,设长为w,宽为h。

大概就是,把一个点沿一个方向,假如说是x轴,沿x轴向正方向延长w个长度,然后这是一条入边,在y+h+1上,建一条相应的出边,就是权值取个负数,就相当于把这条边又给删去啦。

然后将所有的边按y排序,根据y从小到大,加入边,就是更新(x,x+w)这个区间。想想,这样的话,某一点 x0就可以有x0为右边界的矩形的框住的权值和,然后y又是从下往上扫的,而且还有出边,所以(x0,y0)表示以这个点为右上角的矩形框住的权值和。

比如我们更新到了y=yi,在把所有y=yi的边都更新之后,线段树存的是x,对应的最大值。所以线段树的根的最大值,就代表在y=yi下(xi,yi)为右上角的矩形框住最大权值和。

然后y从0扫到最大值,就可以得到最大权值和啦。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 10002
#define uint unsigned int
uint x_data[maxn * 2], y_data[maxn * 2];
struct Node
{
	unsigned int x, y;
	int val;
	void made(unsigned int a, unsigned int b,int c)
	{
		x = a, y = b, val = c;
	}
}node[maxn];
struct edge_mode
{
	int y, l, r, val;
	void edge_make(int y, int l, int r, int val)
	{
		this->y = y;
		this->l = l;
		this->r = r;
		this->val = val;
	}
}edge[20005];
struct segment
{
	int add, max;
}segtree[160005];
bool cmp(edge_mode a, edge_mode b)
{
	if (a.y < b.y) return true;
	else return false;
}
void init(int id, int l, int r)
{
	segtree[id].add = segtree[id].max = 0;
	if (l == r) return;
	init(id << 1, l, (l + r) >> 1);
	init(id << 1 | 1, ((l + r) >> 1) + 1, r);
}
void update(int id, int l, int r, int nl, int nr, int val)
{
	if (r<nl || l>nr) return;
	if (l >= nl&&r <= nr)
	{
		segtree[id].add += val;
		segtree[id].max += val;
		return;
	}
	update(id << 1, l, (l + r) >> 1, nl, nr, val);
	update(id << 1 | 1, ((l + r) >> 1) + 1, r, nl, nr, val);
	segtree[id].max = max(segtree[id << 1].max, segtree[id << 1 | 1].max) + segtree[id].add;
}
int main()
{
	//freopen("input.txt", "r", stdin);
	int n, w, h;
	while ((scanf("%d%d%d", &n, &w, &h)) == 3)
	{
		--w, --h;
		init(1, 0, 20000);
		//unsigned int x, y;
		for (int i = 0; i < n; ++i)
		{
			scanf("%u%u%d", &node[i].x, &node[i].y, &node[i].val);
			x_data[2 * i] = node[i].x, x_data[2 * i + 1] = node[i].x + w;
			y_data[2 * i] = node[i].y, y_data[2 * i + 1] = node[i].y + h + 1;
		}
		sort(x_data, x_data + 2 * n);
		sort(y_data, y_data + 2 * n);
		uint x_d = unique(x_data, x_data + 2 * n) - x_data, y_d = unique(y_data, y_data + 2 * n) - y_data;
		for (int i = 0; i < n; ++i)
		{
			int x1 = lower_bound(x_data, x_data + x_d, node[i].x) - x_data;
			int y1 = lower_bound(y_data, y_data + y_d, node[i].y) - y_data;
			int x2 = lower_bound(x_data, x_data + x_d, node[i].x + w) - x_data;
			int y2 = lower_bound(y_data, y_data + y_d, node[i].y + h + 1) - y_data;
			edge[2 * i].edge_make(y1, x1, x2, node[i].val);
			edge[2 * i + 1].edge_make(y2, x1, x2, -1 * node[i].val);
			//printf("%d %d %d %d %d\n", x1, y1, x2, y2, node[i].val);
		}
		sort(edge, edge + 2 * n, cmp);
		int ans = 0;
		for (int i = 0, t = 0; i <= 20000; i++)
		{
			while (edge[t].y == i&&t < 2 * n)
			{
				update(1, 0, 20000, edge[t].l, edge[t].r, edge[t].val);
				t++;
			}
			//if (i <= 5)
				//printf("%d\n", segtree[1].max);
			ans = max(ans, segtree[1].max);
		}
		printf("%d\n", ans);
	}
	//while (1);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值