【POJ 2482】【扫描线问题】Stars in Your Window【包星星问题】

题意:

      给出一大堆星星的坐标,给出每个星星的亮度。然后给出一个矩形,要求用这个矩形包住的星星的亮度最大。注意:如果星星在矩形边界上,则不计算这个星星的亮度。

【ps:本题的description是一封极美的情书,文采非常棒,强推!】

思路:

      我们来思考一下,一个矩形的位置是不是由这个矩形右上角这个点所决定的,所以我们可以把考虑矩形的位置改为考虑右上角这个点所在的位置。

      然后我们可以发现,对于一颗星星,(x,y),只要右上角这个点在(x+0.1,y+0.1)~(x+w-0.1,y+h-0.1)这个范围内,即可包住这颗星星。此处取0.1的原因是星星不能在矩形边界上。

      因此一个星星就可以确定一个矩形,那么本题就变成了给出一大堆矩形,每个矩形都有一个权值,问其中哪一个区域矩形值之和最大。

      因此我们可以将每个矩形的左右边界抽离出来,然后就变成了区间覆盖问题。

      询问在线段树维护下的这根扫描线上亮度最大的值是多少,所以线段树上只需要维护一个最大值,再加上一个lazy标记,然后边插入边,边更新ans,就可以通过此题。

总结:

      扫描线的问题都大同小异,核心在于求出由线段树维护的这一根线上被覆盖的最长长度,或者某一个亮度最大的点的值,维护一下sum或者维护一下max就可以解决问题。

      关键点还是在于如何扫的问题上,弄清楚如何扫,接下来的就只是码代码了。

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
const int N = 100000;

struct Line{
	double x,y1,y2;
	int flag;
}line[N];

bool cmp(Line a,Line b)
{
	return a.x < b.x;
}

int n,w,h,num,ans;
double y[N];

struct Tree{
	int l,r,lazy;
	double ml,mr;
	int maxn;
}t[N*4];

void build(int p,int l,int r)
{
	t[p].l = l, t[p].r = r, t[p].ml = y[l], t[p].mr = y[r], t[p].maxn = 0, t[p].lazy = 0;
	if(l == r) return;
	int mid = (l+r)>>1;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}

void pushup(int p)
{
	if(t[p].lazy != 0)
	{
		t[p*2].lazy += t[p].lazy;
		t[p*2+1].lazy += t[p].lazy;
		t[p*2].maxn += t[p].lazy;
		t[p*2+1].maxn += t[p].lazy;
		t[p].lazy = 0;
	}
}

void change(int p, Line a)
{
//	cout << a.y1 << " " << a.y2 << endl;
	if(a.y1 <= t[p].ml && t[p].mr <= a.y2)
	{
	//	t[p].s += a.flag;
		t[p].lazy += a.flag;
		t[p].maxn += a.flag;
		return;
	}
	pushup(p);
	if(t[p*2].mr >= a.y2) change(p*2,a);
	else if(t[p*2+1].ml <= a.y1) change(p*2+1,a);
	else{
		change(p*2,a);
		change(p*2+1,a);
	}
	t[p].maxn = max(t[p*2].maxn,t[p*2+1].maxn);
}	

int main()
{
	while(~scanf("%d%d%d",&n,&w,&h))
	{
		ans = 0, num = 0;
		rep(i,1,n)
		{
			double x1,y1,z1;
			scanf("%lf%lf%lf",&x1,&y1,&z1);
			line[++num].x = x1+0.1, line[num].y1 = y1+0.1, line[num].y2 = y1+h-0.1, y[num] = y1+0.1, line[num].flag = z1;
			line[++num].x = x1+w-0.1, line[num].y1 = y1+0.1, line[num].y2 = y1+h-0.1, y[num] = y1+h-0.1, line[num].flag = -z1;	
		}
		sort(line+1,line+1+num,cmp);
		sort(y+1,y+1+num);
		int scr = unique(y+1,y+1+num)-y-1;
		build(1,1,scr);

		rep(i,1,num)
		{
			change(1,line[i]);
			ans = max(ans,t[1].maxn);
		}
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/83215145