【题解】窗口的星星
前置芝士 扫描线#
题目大意就是,问窗口能框住的最大亮度。
转化一下题意,把每一颗星星扩展为一个长宽为\(H,W\)的矩形,在矩形里面,都是可以框住这颗星星的。
那么问题就转化为,求一些矩形的最大面积并。
显然扫描线做。线段树维护区间加的亮度,同时维护\(MAX\),查询的时候,一次次加边,一次次更新答案即可。
注意数据大,需要离散化。用\(sort,unique\)就很方便。
其中,我的\(LowerBound\)是手写的\(find\)函数。
\(Code:\)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
const int MAXN=5000000;
int T,n,tot,rec,val[MAXN];
int rk[MAXN],W,H,Ans,ans;
struct SegmentTree{
int l,r,tag,v;
}tr[MAXN];
struct Line{
int l,h,v,x;
bool operator<(const Line&A)const{
return h<A.h;
}
}e[MAXN];
void build(int l,int r,int x){
tr[x].l=l;
tr[x].r=r;
tr[x].tag=tr[x].v=0;
if(l==r)return;
int mid=l+r>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
}
inline void pushdown(int x){
if(tr[x].tag){
tr[x<<1].tag+=tr[x].tag;
tr[x<<1|1].tag+=tr[x].tag;
tr[x<<1].v+=tr[x].tag;
tr[x<<1|1].v+=tr[x].tag;
tr[x].tag=0;
}
}
void change(int x,int l,int r,int k){
if(tr[x].l>=l&&tr[x].r<=r){
tr[x].tag+=k;
tr[x].v+=k;
pushdown(x);
return;
}
pushdown(x);
int mid=(tr[x].l+tr[x].r)>>1;
if(l<=mid)change(x<<1,l,r,k);
if(mid<r)change(x<<1|1,l,r,k);
tr[x].v=max(tr[x<<1].v,tr[x<<1|1].v);
}
inline bool cmp(Line A,Line B){
if(A.x==B.x)return A.v>B.v;
else return A.x<B.x;
}
int find(int x){
int l=1,r=rec,A;
while(l<=r){
int mid=l+r>>1;
if(rk[mid]==x)return mid;
else if(rk[mid]>x)r=mid-1,A=r;
else if(rk[mid]<x)l=mid+1,A=l;
}
return A;
}
void query(int x,int l,int r){
if(tr[x].l>=l&&tr[x].r<=r){
ans=max(ans,tr[x].v);
return;
}
pushdown(x);
int mid=tr[x].l+tr[x].r>>1;
if(l<=mid)query(x<<1,l,r);
if(mid<r)query(x<<1|1,l,r);
}
signed main(){
scanf("%lld",&T);
while(T--){
n=W=H=0;
tot=0,rec=0,Ans=0,ans=0;
memset(val,0,sizeof(val));
memset(rk,0,sizeof(rk));
scanf("%lld%lld%lld",&n,&W,&H);
for(int i=1,x,y,v;i<=n;++i){
scanf("%lld%lld%lld",&x,&y,&v);
int x1=x-W,y1=y-1,x2=x-1,y2=y-H;
e[(i<<1)-1].x=x1,e[i<<1].x=x2;
e[(i<<1)-1].h=e[i<<1].h=y2;
e[(i<<1)-1].l=e[i<<1].l=y1;
e[(i<<1)-1].v=v;e[i<<1].v=-v;
rk[++tot]=y1,rk[++tot]=y2;
}
sort(rk+1,rk+tot+1);
rec=unique(rk+1,rk+tot+1)-rk-1;
for(int i=1;i<=(n<<1);++i){
int pos1=find(e[i].h);
int pos2=find(e[i].l);
val[pos1]=e[i].h;
val[pos2]=e[i].l;
e[i].h=pos1;e[i].l=pos2;
}
sort(e+1,e+(n<<1|1),cmp);
build(1,(n<<1),1);
for(int i=1;i<=(n<<1);++i){
change(1,e[i].h,e[i].l,e[i].v);
query(1,e[i].h,e[i].l);
Ans=max(Ans,ans);
}
printf("%lld\n",Ans);
}
return 0;
}
有时间准备扫描线讲解,准备历史去\(QAQ\)