HDU - 5091 Beam Cannon 线段树 扫描线

题目链接:点击查看

题意:给你n个点的坐标,给你一个矩形的w,h,问最多能圈住多少点

题解:扫描线,按x轴进行扫描,其实就是把一个点的左右范围找出来,一个为正,一个为负,把y对应的区间更新一下即可,我对y离散化了一下,其实不离散化也行,我们吧初始都加为正,y最多80000,时间也差不多。

#include <bits/stdc++.h>
using namespace std;
const int N = 80010;
struct node {
	int l, r;
	int val,laz;
}tree[N << 2];
struct Point {
	int x, y1, y2;
	int val;
}p[20010];
int n, w, h;
int b[20010];
int cmp(Point x,Point y)
{
	if(x.x!=y.x)return x.x<y.x;
	else return x.val>y.val;
}
void build(int l,int r,int cur)
{
	tree[cur].l=l;
	tree[cur].r=r;
	tree[cur].val=0;
	tree[cur].laz=0;
	if(l==r)return;
	int mid=(l+r)>>1;
	build(l,mid,cur<<1);
	build(mid+1,r,cur<<1|1);
}
void pushup(int cur)
{
	tree[cur].val=max(tree[cur<<1].val,tree[cur<<1|1].val);
}
void pushdown(int cur)
{
	if(tree[cur].laz)
	{
		tree[cur<<1].laz+=tree[cur].laz;
		tree[cur<<1].val+=tree[cur].laz;
		tree[cur<<1|1].val+=tree[cur].laz;
		tree[cur<<1|1].laz+=tree[cur].laz;
		tree[cur].laz=0;
	}
}
void update(int pl,int pr,int cur,int val)
{
	if(pl<=tree[cur].l&&tree[cur].r<=pr)
	{
		tree[cur].val+=val;
		tree[cur].laz+=val;
		return;
	}
	pushdown(cur);
	int mid=(tree[cur].l+tree[cur].r)>>1;
	if(pl<=mid) update(pl,pr,cur<<1,val);
	if(pr>mid) update(pl,pr,cur<<1|1,val);
	pushup(cur);
}
int main() {
	int x, y;
	int y1,y2;
	while(~scanf("%d", &n)) {
		if(n < 0) break;
		scanf("%d %d", &w, &h);
		for(int i = 1; i <= n; i++) {
			scanf("%d %d", &x,&y);
			p[i*2-1].x=x+20001;
			p[i*2-1].y1=y+20001;
			p[i*2-1].y2=y+20001+h;
			p[i*2-1].val=1;
			p[i*2].x=x+20001+w;
			p[i*2].y1=y+20001;
			p[i*2].y2=y+20001+h;
			p[i*2].val=-1;
			b[i*2-1]=y+20001;
			b[i*2]=y+20001+h;
		}
		sort(p+1,p+1+n*2,cmp);
		sort(b+1,b+1+n*2);
		int len=unique(b+1,b+1+n*2)-(b+1);
		build(1,len,1);
		int ans=0;
		for(int i=1;i<=n*2;i++)
		{
			
			y1=lower_bound(b+1,b+1+len,p[i].y1)-b;
			y2=lower_bound(b+1,b+1+len,p[i].y2)-b;
			
			
			update(y1,y2,1,p[i].val);
			ans=max(ans,tree[1].val);
		}
		printf("%d\n",ans);
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/88572866