[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
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Wolfycz/p/8414586.html