题目:POJ2482.
题目大意:给定一个平面上的
n
n
n个点
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi),价值为
c
i
c_i
ci,现在要求用一个长为
w
w
w宽为
h
h
h的矩形覆盖的点价值和最大(边界上的不算).
x
i
,
y
i
,
w
,
h
∈
N
+
,
1
≤
n
≤
1
0
4
,
1
≤
w
,
h
≤
1
0
6
,
0
≤
x
i
,
y
i
<
2
31
x_i,y_i,w,h\in N_+,1\leq n\leq 10^4,1\leq w,h\leq 10^6,0\leq x_i,y_i< 2^{31}
xi,yi,w,h∈N+,1≤n≤104,1≤w,h≤106,0≤xi,yi<231.
首先考虑由于坐标是整数,所以不能算上边界可以直接转化为长宽均减 1 1 1.
我们可以转化一下,把每个点转化成一个矩形,表示只要用于覆盖的矩形的右上角在这个点对应点矩形之中,这个点就会有贡献.很容易发现点 i i i对应的矩形左下角为 ( x i , y i ) (x_i,y_i) (xi,yi),右上角为 ( x i + w − 1 , y i + h − 1 ) (x_i+w-1,y_i+h-1) (xi+w−1,yi+h−1).
现在问题就变成了在一个平面上寻找一个点,使得包含这个点的矩形权值和最大.
然后我们就可以把 n n n个矩形变成 2 n 2n 2n条扫描线,并且用线段树维护就好了.
时间复杂度 O ( n log n ) O(n\log n) O(nlogn).
代码如下:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
#define Abigail inline void
typedef long long LL;
#define int unsigned int //注意,这道题坐标大小加个10^6都能爆int
const int N=10000;
int n,w,h;
struct seg{
int x,l,r,v;
seg(int X=0,int L=0,int R=0,int V=0){x=X;l=L;r=R;v=V;}
bool operator < (const seg &p)const{return x<p.x;}
}e[N*2+9];
int ord[N*2+9],ans;
int lower(int k){
int l=1,r=n<<1,mid=l+r>>1;
for (;l<r;mid=l+r>>1)
k>ord[mid]?l=mid+1:r=mid;
return l;
}
int upper(int k){
int l=1,r=n<<1,mid=l+r>>1;
for (;l<r;mid=l+r+1>>1)
k<ord[mid]?r=mid-1:l=mid;
return l;
}
struct tree{
int max,tag;
}tr[N*8+9];
void Pushup(int k){tr[k].max=max(tr[k<<1].max,tr[k<<1|1].max);}
void Update_add(int k,int v){tr[k].max+=v;tr[k].tag+=v;}
void Pushdown(int k){Update_add(k<<1,tr[k].tag);Update_add(k<<1|1,tr[k].tag);tr[k].tag=0;}
void Change_add(int L,int R,int v,int l,int r,int k=1){
if (L==l&&R==r) {Update_add(k,v);return;}
int mid=l+r>>1;
Pushdown(k);
if (R<=mid) Change_add(L,R,v,l,mid,k<<1);
else if (L>mid) Change_add(L,R,v,mid+1,r,k<<1|1);
else Change_add(L,mid,v,l,mid,k<<1),Change_add(mid+1,R,v,mid+1,r,k<<1|1);
Pushup(k);
}
Abigail into(){
int x,y,c;
for (int i=1;i<=n;++i){
scanf("%u%u%u",&x,&y,&c);
e[i*2-1]=seg(x,y,y+h-1,c);e[i*2]=seg(x+w,y,y+h-1,-c); //减去的时候在x+w处减去更好处理
ord[i*2-1]=y;ord[i*2]=y+h-1;
}
}
Abigail work(){
ans=0;
sort(e+1,e+1+2*n);
sort(ord+1,ord+1+2*n);
for (int i=1;i<=n<<1;++i)
e[i].l=lower(e[i].l),e[i].r=upper(e[i].r); //注意取两边端点
for (int i=1;i<=n<<1;){
for (int now=e[i].x;i<=n<<1&&e[i].x==now;++i) Change_add(e[i].l,e[i].r,e[i].v,1,n<<1);
ans=max(ans,tr[1].max);
}
}
Abigail outo(){
printf("%u\n",ans);
}
#undef int
int main(){
while (~scanf("%u%u%u",&n,&w,&h)){
into();
work();
outo();
}
return 0;
}