hdu 5091 (线段树,扫描线)

Beam Cannon

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1049    Accepted Submission(s): 401


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
 

Source

2014上海全国邀请赛——题目重现(感谢上海大学提供题目)



题目大意:一个图上有N个点,每个点给出坐标,有一个W*H的矩形,这个矩形和x,y轴平行,问你怎么放置这个矩形,能让矩形里的点最多。


有两种解法:


第一种:枚举每个点为矩形的最左下角,统计出每个矩形的点,求出最大值即可。//不过此题不行,超时。


第二种:扫描线解法,把每个原点(x,y)对应再来个映点(x+w,y),这样就有2N个点。这N个原点每次在区间【y,y+h】加1,而N个映点在区间【y,y+h】减1。其实思路就是把每个原点对应在可以存在的范围内,映点出现时,就把这个原点销去,表示这个原点已经超出了范围。以y轴做线段树,我们把整个线段树存的值看做了每个位置存在的点数,求出每个位置的最大值就是我们要求的结果,不懂得话自己画个图就好理解了。


代码:


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define mem(p,k) memset(p,k,sizeof(p));
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define inf 0x6fffffff
#define LL long long
#define MAXN 20000
using namespace std;
int col[MAXN<<2];
int maxx[MAXN<<2],X[MAXN],lbd[MAXN<<2],rbd[MAXN<<2],sum[MAXN<<2];
struct Seg{
    int x,y;
    int cur;
    Seg(){}
    Seg(int a,int b,int d):x(a),y(b),cur(d){}
    bool operator <(const Seg &a)const{
        if(a.x==x)return cur>a.cur;
        return x<a.x;
   }
}ss[MAXN];
void pushup(int rt){

    maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);

}
void pushdown(int rt){
    if(col[rt]){
        col[rt<<1]+=col[rt];
        col[rt<<1|1]+=col[rt];
        maxx[rt<<1]+=col[rt];
        maxx[rt<<1|1]+=col[rt];
        col[rt]=0;
    }
}
void update(int L,int R,int c,int l,int r,int rt){
    if(L<=l&&R>=r){
        col[rt]+=c;
        maxx[rt]+=c;
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(R>m) update(L,R,c,rson);
    pushup(rt);
}

int main(){
    int n,w,h,k,lbd,rbd;
    int pp=0;
    while(cin>>n&&~n){
        cin>>w>>h;
        k=0,lbd=inf,rbd=-inf;
        for(int i=0;i<n;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            lbd=min(lbd,b);
            rbd=max(rbd,b);
            ss[k++]=Seg(a,b,1);
            ss[k++]=Seg(a+w,b,-1);
        }
        sort(ss,ss+k);
        int ans=0;
        for(int i=0;i<k;i++){
            update(ss[i].y,ss[i].y+h,ss[i].cur,lbd,rbd,1);
            ans=max(ans,maxx[1]);
        }
        cout<<ans<<endl;
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值