题意:给出n个星星的坐标,每个星星有一个亮度,给出一个矩形的长和宽,问矩形能包括的星星的最大亮度和(不包括边框)。
思路: 平面上有若干个区域,每个区域都带有一个权值,求在那个实际上重叠的区域权值和最大。使用扫描线算法,取出每个区域的左右边界,保存2个四元组,(x,y,y+h,c) (x+w,y,y+h,-c),按照第一维的大小排序。同时关于y建立一颗线段树,维护区间最大值max1,可以认为线段树上的一个值y代表区间[y,y+1] 而区间[y,y+1+h]表示线段树中的y y+1 y+2…y+h这样线段树所维护的值便是由几个数字构成的序列了。。
逐一扫描每个四元组,在线段树中执行区间修改(可以使用延迟标记)把[y1,y2]中的每个数加c,然后用根节点更新答案
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <cmath>
using namespace std;
#define MAXN 205
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2,r,rt<<1|1
struct Line //四元组
{
int x,y1,y2;
int flag;
}c[MAXN];
struct Node //关于纵坐标y建立起一颗线段树
{
int l,r;//线段树的左右整点
int max1;//max1记录最大值
int lazy;//
//len用来计算实在的长度,rf,lf分别是对应的左右真实的浮点数端点
}a[MAXN*3];
int cnt,numy,max1;
double y[MAXN];//记录y坐标的数组
bool cmp(Line a,Line b)//扫描线算法排序的函数
{
if(a.x!=b.x)
return a.x < b.x;
else
return a.flag<b.flag;
}
void pushup(int rt)
{
a[rt].max1=max(a[rt<<1].max1,a[rt<<1|1].max1)+a[rt].lazy;
}
void Build(int rt,int l,int r)//构造线段树
{
a[rt].max1=a[rt].lazy=0;
a[rt].l=y[l];
a[rt].r=y[r];
if(l+1==r) return;
int mid=(l+r)>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid,r);//递归构造
}
void update(int L,int R,int K,int rt)//加入线段e,后更新线段树
{
if(L<=a[rt].l&&a[rt].r<=R){
a[rt].lazy+=K;
a[rt].max1+=K;
return ;
}
if(L<a[rt<<1].r)
update(L,min(R,a[rt<<1].r),K,rt<<1);
else if(a[rt<<1|1].l<R)
update(max(a[rt<<1|1].l,L),R,K,rt<<1|1);
pushup(rt);
}
int main()
{
int n,w,h;
while(scanf("%d%d%d",&n,&w,&h)==3){
int x,y1,k,max1=-1000000;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x,&y1,&k);
c[cnt].x=x;
c[cnt].y1=y1;
c[cnt].y2=y1+h;
c[cnt].flag=k;
cnt++;
c[cnt].x=x+w;
c[cnt].y1=y1;
c[cnt].y2=y1+h;
c[cnt].flag=-k;
cnt++;
y[numy++]=y1; y[numy++]=y1+h;
}
cnt--; numy--;
sort(y+1,y+numy+1); //排序
numy=unique(y+1,y+1+numy)-(y+1); //去重
sort(c,c+cnt,cmp);
Build(1,numy,1);
for(int i=0;i<cnt;i++){
update(c[i].y1,c[i].y2,c[i].flag,1);
max1=max(max1,a[1].max1);
}
printf("%d\n",max1);
}
}