1. 程式人生 > >【POJ 2482】【掃描線問題】Stars in Your Window【包星星問題】

【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;
}