POJ 2482 Stars in Your Window(线段树扫描线)

题意:

给出星星的坐标和亮度,给定一个矩形(/),求框住的星星亮度和的最大值,恰好在边上的不算

对于每颗星星我们以左下角构成一个矩形两条边一条范围[x,x+w),高度为y,权值为brightness,另一条范围[x,x+w),高度为y+h,亮度为-brightness。样我们对所有边进行排序从低到高扫描就行了计算线段最大覆盖次数即可

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define MID(x,y) ( ( x + y ) >> 1 )  
#define L(x) ( x << 1 )  
#define R(x) ( x << 1 | 1 )  
#define FOR(i,s,t) for(int i=s; i<t; i++)  
using namespace std;
const int MAX = 20010;
struct point { int x, y; long long lx, ly, rx, ry; int val; };
point p[MAX / 2];
long long x[MAX], y[MAX];
int ans;
struct Sline { int x, y1, y2; int flag; };
Sline l[MAX];
void add_line(int x1, int y1, int x2, int y2, int &cnt, int flag)
{
	l[cnt].x = x1; l[cnt].y1 = y1; l[cnt].y2 = y2;
	l[cnt++].flag = flag;
	l[cnt].x = x2; l[cnt].y1 = y1; l[cnt].y2 = y2;
	l[cnt++].flag = -flag;
}
bool cmp(Sline a, Sline b)
{
	if (a.x == b.x) return a.flag < b.flag;
	return a.x < b.x;
}
struct Tnode {               // 一维线段树   
	int l, r, val, max;
	int len() { return r - l; }
	int mid() { return MID(l, r); }
	bool in(int ll, int rr) { return l >= ll && r <= rr; }
	void lr(int ll, int rr) { l = ll; r = rr; }
};
Tnode node[MAX << 2];
void Build(int t, int l, int r)
{
	node[t].val = node[t].max = 0;
	node[t].lr(l, r);
	if (node[t].len() == 1) return;
	int mid = MID(l, r);
	Build(L(t), l, mid);
	Build(R(t), mid, r);
}
void Updata(int t, int l, int r, int val)
{
	if (node[t].in(l, r))
	{
		node[t].val += val;
		node[t].max += val;
		ans = max(node[t].max, ans);
		return;
	}
	if (node[t].len() == 1) return;
	node[L(t)].val += node[t].val;
	node[L(t)].max += node[t].val;
	node[R(t)].val += node[t].val;
	node[R(t)].max += node[t].val;
	node[t].val = 0;
	int mid = node[t].mid();
	if (l >= mid)
		Updata(R(t), l, r, val);
	else
		if (r <= mid)
			Updata(L(t), l, r, val);
		else
		{
			Updata(L(t), l, r, val);
			Updata(R(t), l, r, val);
		}
	node[t].max = max(node[L(t)].max, node[R(t)].max);
	ans = max(node[t].max, ans);
}

int solve(int cx, int cy, int n)
{
	sort(x, x + cx);
	sort(y, y + cy);
	cx = unique(x, x + cx) - x;
	cy = unique(y, y + cy) - y;
	int cnt = 0;
	FOR(i, 0, n)
	{
		int x2 = lower_bound(x, x + cx, p[i].rx) - x;
		int y2 = lower_bound(y, y + cy, p[i].ry) - y;
		int x1 = lower_bound(x, x + cx, p[i].lx) - x;
		int y1 = lower_bound(y, y + cy, p[i].ly) - y;
		add_line(x1, y1, x2, y2, cnt, p[i].val);
	}
	sort(l, l + cnt, cmp);
	Build(1, 0, cy + 1);
	FOR(i, 0, cnt)
		Updata(1, l[i].y1, l[i].y2, l[i].flag);
	return ans;
}

int main()
{
	int l;
	int n, w;
	while (scanf("%d%d%d", &n, &w, &l) != EOF)
	{
		int cntx = 0, cnty = 0;
		ans = 0;
		FOR(i, 0, n)
		{
			scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].val);
			p[i].lx = p[i].x; p[i].ly = p[i].y;
			p[i].rx = p[i].x * 1ll + w; p[i].ry = p[i].y * 1ll + l;
			x[cntx++] = p[i].lx;
			x[cntx++] = p[i].rx;
			y[cnty++] = p[i].ly;
			y[cnty++] = p[i].ry;
		}
		solve(cntx, cnty, n);
		printf("%d\n", ans);
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值