hdu 5091 线段树+扫描线思想



链接:戳这里


Beam Cannon

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Problem Description
Recently, the γ galaxies broke out Star Wars. Each planet is warring for resources. In the Star Wars, Planet X is under attack by other planets. Now, a large wave of enemy spaceships is approaching. There is a very large Beam Cannon on the Planet X, and it is very powerful, which can destroy all the spaceships in its attack range in a second. However, it takes a long time to fill the energy of the Beam Cannon after each shot. So, you should make sure each shot can destroy the enemy spaceships as many as possible.

To simplify the problem, the Beam Cannon can shot at any area in the space, and the attack area is rectangular. The rectangle parallels to the coordinate axes and cannot rotate. It can only move horizontally or vertically. The enemy spaceship in the space can be considered as a point projected to the attack plane. If the point is in the rectangular attack area of the Beam Cannon(including border), the spaceship will be destroyed.
 
Input
Input contains multiple test cases. Each test case contains three integers N(1<=N<=10000, the number of enemy spaceships), W(1<=W<=40000, the width of the Beam Cannon’s attack area), H(1<=H<=40000, the height of the Beam Cannon’s attack area) in the first line, and then N lines follow. Each line contains two integers x,y (-20000<=x,y<=20000, the coordinates of an enemy spaceship). 

A test case starting with a negative integer terminates the input and this test case should not to be processed.
 
Output
Output the maximum number of enemy spaceships the Beam Cannon can destroy in a single shot for each case.
 
Sample Input
2 3 4
0 1
1 0
3 1 1
-1 0
0 1
1 0
-1
 
Sample Output
2
2


题意:

二维平面上给出n个点,给定固定的矩形大小,问任意放置矩形,最多可以覆盖多少个点


思路:

1:窗口的位置不固定,也就是在平面上移动

这里讲下扫描线的原理,已知一个矩形,当前位置x对于矩形下边的加入,必定在x+width的位置线段要出去

 类似这样的思想,现在我们在滑动窗口找出覆盖最多的点的位置,那么必定对应一些点由于窗口的移动而从窗口出去,同样也会有新的点进来,那么我们怎么处理可以使得点它自己进来或者自己消失呢?

扫描线思想,对于每个平面上的点(x,y,1)都一一对应一个点(x+W,y,-1)  (两处的y都未知)表示窗口出去的时候,当前区域内的点的个数-1,点进来的时候,窗口的数目+1

2:那么只需要把点按x关键字从小到大排序,每次加入一个点,判断这个点是出来还是进去的

现在就是怎么快速求出 ,在已知当前点y的坐标的情况下,区域内点的个数?

这样想:由于每个点(x,y)可以影响到的Y轴的范围是:y-H,y+H,那么我们直接把每个点都简化成一条朝上的线段铺在Y轴上,这样的话只需要求出Y轴上被覆盖次数的那个点的覆盖次数就知道答案了,线段树维护就可以了!


代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,H,W;
const int N=10005;
struct point{
	int x,y,v;
	point(int x=0,int y=0,int v=0){}
	bool operator < (const point &a)const{
		if(x==a.x) return v<a.v;
		return x<a.x;
	}
}s[2*N];
struct node{
	int f,v;
}tr[4000100];
void build(int root,int l,int r){
    tr[root].f=0;
    tr[root].v=0;
	if(l==r) return ;
	int mid=(l+r)/2;
	build(root*2,l,mid);
	build(root*2+1,mid+1,r);
}
void pushdown(int root){
	if(tr[root].f){
		tr[root*2].f+=tr[root].f;
		tr[root*2+1].f+=tr[root].f;
		tr[root*2].v+=tr[root].f;
		tr[root*2+1].v+=tr[root].f;
		tr[root].f=0;
	}
}
void update(int root,int l,int r,int x,int y,int v){
	if(x<=l && y>=r){
		tr[root].f+=v;
		tr[root].v+=v;
		return ;
	}
	pushdown(root);
	int mid=(l+r)/2;
	if(y<=mid) update(root*2,l,mid,x,y,v);
	else if(x>mid) update(root*2+1,mid+1,r,x,y,v);
	else {
		update(root*2,l,mid,x,mid,v);
		update(root*2+1,mid+1,r,mid+1,y,v);
	}
	tr[root].v=max(tr[root*2].v,tr[root*2+1].v);
}
int main(){
	while(scanf("%d",&n)!=EOF){
		if(n==-1) break;
		scanf("%d%d",&W,&H);
		for(int i=1;i<=2*n;i+=2){
            int x,y;
            scanf("%d%d",&x,&y);
            y+=20000;
            s[i].x=x;
            s[i].y=y;
            s[i].v=1;
            s[i+1].x=x+W+1;
            s[i+1].y=y;
            s[i+1].v=-1;
		}
		sort(s+1,s+2*n+1);
		build(1,0,8*N);
		int ans=0;
		for(int i=1;i<=2*n;i++){
			update(1,0,8*N,s[i].y,s[i].y+H,s[i].v);
			ans=max(ans,tr[1].v);
		}
		printf("%d\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值