【HDU5091】Beam Cannon,扫描线+线段树

传送门
思路:
扫描线的经典问题
然而并不是很会做……
对x坐标差分一下(例如(x,y)类型为1,(x+w,y)的类型就是-1,以便于之后扫描可以去除该点),然后对y坐标转化为正数(便于操作为线段树上的区间,因为这里坐标值都很小所以不用离散化,加上一个较大值就可以了)
每次加1的点(-1点就是消去原先的1点了)时实际上是区间覆盖操作,表示该点与矩形的相对位置,然后查一下最大值就行了
总的来说就是差分加点+扫描线+线段树的区间覆盖,单点查max
代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define M 10005
using namespace std;
int n,X,Y;
int tr[M<<3],lazy[M<<3]; 
struct node{
    int x,y,tp;
}a[M<<1];
int in()
{
    int t=0;char ch=getchar();bool f=0;
    while (ch>'9'||ch<'0') f=(ch=='-'),ch=getchar();
    while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
    return f?-t:t;
}
bool cmp(node a,node b){return a.x<b.x;}
void pushdown(int rt)
{
    if (!lazy[rt]) return;
    lazy[rt<<1]+=lazy[rt];
    lazy[rt<<1|1]+=lazy[rt];
    tr[rt<<1]+=lazy[rt];
    tr[rt<<1|1]+=lazy[rt];
    lazy[rt]=0;
}
void update(int rt,int begin,int end,node now)
{
    if (now.y<=begin&&end<=now.y+Y)
    {
        lazy[rt]+=now.tp;
        tr[rt]+=now.tp;
        return;
    }
    pushdown(rt);
    int mid=begin+end>>1;
    if (mid>=now.y) update(rt<<1,begin,mid,now);
    if (mid<now.y+Y) update(rt<<1|1,mid+1,end,now);
    tr[rt]=max(tr[rt<<1],tr[rt<<1|1]);
}
void work()
{
    X=in();Y=in();
    int S=1<<30,T=-1<<30;
    for (int i=1;i<=n;++i)
        a[i*2-1]=(node){in(),in()+20000,1},
        a[i*2]=(node){a[i*2-1].x+X+1,a[i*2-1].y,-1},
        S=min(a[i<<1].y,S),T=max(a[i<<1].y,T);
    sort(a+1,a+n*2+1,cmp);
    int ans=0;
    for (int i=1;i<=n<<1;++i)
        update(1,S,T,a[i]),
        ans=max(ans,tr[1]);
    printf("%d\n",ans);
}
main()
{
    for (n=in();n>0;n=in()) work();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值