解题思路: 首先注意到最优解肯定是窗子的右上角(或其他角)在某个星星位置处(这里的在是模糊的在,略微比星星的位置大一点,能包含这个星星就行)。这样就将问题变成离散空间上的问题了。然后问题关键就是将二维问题变成一维问题,先只考虑x轴方向的一维,可以想到一个星星的起到的作用是一条长度为w的线段,然后答案就是找到被最多线段覆盖的某点,就是区间最值问题了。那么再考虑y轴这一维,这一维可以认为是线段的存活时间。那么将星星分成两条线段,一个代表出生,一个代表死亡,然后按照y坐标顺序插入星星(因为在每个y坐标出要么产生一个新的线段,要么减少一个线段,都会改变已有线段树的状态),线段树的作用就是维护一个区间最值。
我觉得类似的问题有林涛论文《线段树的应用》中的例题 “蛇”,也是有类似这种二维变一维,存活时间的思想。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 20005
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
vector<ll> X;
struct StarType{
ll x,y,c;
StarType(){}
StarType(ll x,ll y,ll c)
{
this->x=x,this->y=y,this->c=c;
}
}Star[maxn];
bool cmp(const StarType& a,const StarType& b)
{
if(a.y==b.y)
return a.c<0;
return a.y<b.y;
}
ll Tree[maxn<<2],Lazy[maxn<<2];
void Build()
{
memset(Tree,0,sizeof(Tree));
memset(Lazy,0,sizeof(Lazy));
}
void PushDown(int rt)
{
Tree[rt]+=Lazy[rt];
Lazy[rt<<1]+=Lazy[rt];
Lazy[rt<<1|1]+=Lazy[rt];
Lazy[rt]=0;
}
void Update(ll val,int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
Lazy[rt]+=val;
return ;
}
if(L>r||R<l)
return ;
if(Lazy[rt]!=0)
PushDown(rt);
int mid=(l+r)>>1;
Update(val,L,R,lson);
Update(val,L,R,rson);
Tree[rt]=max(Tree[rt<<1]+Lazy[rt<<1],Tree[rt<<1|1]+Lazy[rt<<1|1]);
return ;
}
ll Query()
{
return Tree[1]+Lazy[1];
}
void Init()
{
X.clear();
Build();
}
int main()
{
int n,w,h,i,j,L,R,l,r;
ll ans;
while(scanf("%d %d %d",&n,&w,&h)!=EOF)
{
Init();
for(i=0;i<n;++i)
{
scanf("%lld %lld %lld",&Star[i].x,&Star[i].y,&Star[i].c);
Star[i+n].x=Star[i].x,Star[i+n].y=Star[i].y+h,Star[i+n].c=-Star[i].c;
X.push_back(Star[i].x);
}
sort(Star,Star+2*n,cmp);
X.resize(distance(X.begin(),unique(X.begin(),X.end())));
sort(X.begin(),X.end());
l=1,r=X.end()-X.begin()+1;
ans=0;
for(i=0;i<2*n;++i)
{
L=lower_bound(X.begin(),X.end(),Star[i].x)-X.begin()+1;
R=lower_bound(X.begin(),X.end(),Star[i].x+w)-X.begin();
Update(Star[i].c,L,R,l,r,1);
ans=max(ans,Query());
}
printf("%lld\n",ans);
}
return 0;
}