提供一个神奇的思路。
首先二维数点能想到扫描线+线段树。
边框不能取,珂以把长、宽都减$1$,因为你可以这么框:
也就是说边界不取整数。
然后将坐标系上每个点扩展为一个矩形:
大概就是这种感觉:把每个点向左下角扩展得到它代表的矩形。
对于每颗星星,把它能影响到的矩形加上它的贡献。
不考虑横坐标,它能影响到的矩形为:$y$到$y+h$的点所代表的所有矩形。
考虑上横坐标,用扫描线,及时删除不在当前横坐标能覆盖的星星。
这样把每个可能的矩形缩成一个点,用线段树维护最大值,边扫边取最大值就行了。
时间复杂度:$O(t·nlogn)$
(说着轻快其实蒟蒻调了好长时间,边界的处理太麻烦了,具体细节还是看代码吧$QAQ$)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define maxn 10005
#define inf 0x3f3f3f3f
#define pn putchar('\n')
#define px(x) putchar(x)
#define ps putchar(' ')
#define pd puts("======================")
#define pj puts("++++++++++++++++++++++")
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
template<typename T>
inline T read(){
T x=0;
int y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
struct Segment_Tree{
long long dat[maxn<<2],tag[maxn<<2];
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
inline void update(int node){
dat[node]=max(dat[ls(node)],dat[rs(node)]);
}
inline void datadown(int node,long long d){
dat[node]+=d;
tag[node]+=d;
}
inline void pushdown(int node){
datadown(ls(node),tag[node]);
datadown(rs(node),tag[node]);
tag[node]=0;
}
void add(int L,int R,int l,int r,int node,long long d){
if(L<=l&&R>=r){
datadown(node,d);
return;
}
if(tag[node])pushdown(node);
int mid=l+r>>1;
if(L<=mid)add(L,R,l,mid,ls(node),d);
if(R>mid)add(L,R,mid+1,r,rs(node),d);
update(node);
}
inline void clear(){
memset(dat,0,sizeof dat);
memset(tag,0,sizeof tag);
}
}st;
int dis[maxn];
//离散化数组
struct POINT{
int x,y,ll,rr;
long long d;
}p[maxn];
//星星:x、y是坐标,ll、rr是它能覆盖的矩形范围,d是亮度
inline bool cmp(POINT x,POINT y){
return x.x<y.x;
}
int main(){
int t=read();
while(t--){
int n=read(),w=read()-1,h=read()-1,len=0,head=1;
//长宽各-1
for(register int i=1;i<=n;++i)
p[i].x=read(),dis[++len]=p[i].y=read(),p[i].d=read<long long>();
dis[++len]=(1ll<<31)-1;
//加了一个无穷大的边界
sort(dis+1,dis+1+len);
sort(p+1,p+1+n,cmp);//把星星按横坐标排序
len=unique(dis+1,dis+1+len)-dis-1;
long long ans=0;
for(register int i=1;i<=n;++i){
p[i].ll=upper_bound(dis+1,dis+1+len,p[i].y)-dis,p[i].rr=upper_bound(dis+1,dis+1+len,p[i].y+h)-dis;
//要用upper_bound,两边是可以等于的
st.add(p[i].ll,p[i].rr,1,len,1,p[i].d);
while(p[i].x-w>p[head].x)st.add(p[head].ll,p[head].rr,1,len,1,-p[head].d),++head;
//通过head头指针删除点
ans=max(ans,st.dat[1]);
}
printf("%lld\n",ans);
st.clear();
}
}