[POI2001]Goldmine

Description

Byteman作为Byteland的The Goldmine(某一公司厂矿)的最有功的雇员之一,即将在年末退休。为了表示对他的
认真勤恳的工作的承认,The Goldmine的管理层愿意奖励他一小块长方形的矿地,此矿地长和宽为s和w且平行于坐
标系统的轴线。长方形矿地的位置可由他自己选。当然,这块地的价值会随着位置的不同而不同。其价值是指这块
区域内天然金矿石的数量(若矿石位于这块地的边缘,我们同样认为他是属于这个区域的)。你们的任务是计算出
这块地的最大可能价值(即:为它选择最佳位置)。为简便起见,我们假定整个金矿的矿区是无穷的,但含有天然
金矿石的区域却是有限的。
要求
写一程序:
1、 读入天然金矿石的位置;
2、 计算这块地的最大可能价值(即:求给定大小的这块地所含的天然金矿石的最大数);
3、 输出结果

Input

第一行为俩正整数s、w,1<=s,w<=10 000,各自代表着此矩形区域平行X轴和Y轴的边的长度。第二行是一正整数n
,1<=n<=15 000,它表示此金矿矿区内天然矿石的数量。接下来的n行,每行为俩用单个空格隔开的整数x、y,-30
000<=x,y<=30 000,它门分别表示了某一天然金矿石的X坐标和Y坐标。

Output

应恰有一整数,表示此块给定大小的矿地的最高价值。

Sample Input
1 2
12
0 0
1 1
2 2
3 3
4 5
5 5
4 2
1 4
0 5
5 0
2 3
3 2

Sample Output
4


这题同样可以用到扫描线的思想
对于每个矿点,它可以向上下左右四个方向延伸,但这并不代表每个点就要考虑四个方向
考虑下如果该点往下有一个最优解,那么下面的某个点必定有向上的最优解,所以我们只考虑每个矿点的两个方向
扫描线在扫描的过程中,如果有矿区离它的距离超过了s(长),就把它踢掉,扫到的点加进来,点在加进来的时候向上方延伸w(宽),操作完之后取\(max\)即可

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())  x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x>=10)   print(x/10);
    putchar(x%10+'0');
}
const int N=1.5e4,limit=3e4;
struct AC{
    int x,y;
    void join(){x=read(),y=read();}
    bool operator <(const AC &a)const{return x<a.x;}
}A[N+10];
struct Segment{
    #define ls (p<<1)
    #define rs (p<<1|1)
    int tree[limit*8+10],Lazy[limit*8+10];
    void add_tag(int p,int v){Lazy[p]+=v,tree[p]+=v;}
    void pushdown(int p){
        if (!Lazy[p])   return;
        add_tag(ls,Lazy[p]),add_tag(rs,Lazy[p]);
        Lazy[p]=0;
    }
    void updata(int p){tree[p]=max(tree[ls],tree[rs]);}
    void change(int p,int l,int r,int x,int y,int t){
        if (x<=l&&r<=y){
            add_tag(p,t);
            return;
        }
        int mid=(l+r)>>1;
        pushdown(p);
        if (x<=mid)  change(ls,l,mid,x,y,t);
        if (y>mid)   change(rs,mid+1,r,x,y,t);
        updata(p);
    }
}T;
int main(){
    int s=read(),w=read(),n=read(),ans=0;
    for (int i=1;i<=n;i++)   A[i].join();
    sort(A+1,A+1+n);
    for (int i=1,j=1;i<=n;i++){
        while (A[j].x<A[i].x-s)  T.change(1,-limit,limit,A[j].y,min(A[j].y+w,limit),-1),j++;
        //踢掉过远的点
        T.change(1,-limit,limit,A[i].y,min(A[i].y+w,limit),1);//加进当前的点,向上延伸
        ans=max(ans,T.tree[1]);
    }
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/Wolfycz/p/8414586.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值