一堆二维点,有点权。
选择一个坐标建饭堂可以收获所有与其曼哈顿距离不超过m的点的点权。
求最大收获。
曼哈顿距离是个菱形。
将坐标轴旋转45度,再进行放缩,转化为图像是正方形的切比雪夫距离。
然后可以经典扫描线。
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=100000+10,maxm=500000+50,mx=200000,up=500000;
int h[maxm],go[maxn*2],nxt[maxn*2],x[maxn],y[maxn],w[maxn];
int tree[maxm*4],ad[maxm*4];
int i,j,k,l,t,n,m,tot,ans;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void add(int x,int y){
go[++tot]=y;
nxt[tot]=h[x];
h[x]=tot;
}
void mark(int p,int v){
tree[p]+=v;
ad[p]+=v;
}
void down(int p){
if (ad[p]){
mark(p*2,ad[p]);
mark(p*2+1,ad[p]);
ad[p]=0;
}
}
void change(int p,int l,int r,int a,int b,int v){
if (l==a&&r==b){
mark(p,v);
return;
}
down(p);
int mid=(l+r)/2;
if (b<=mid) change(p*2,l,mid,a,b,v);
else if (a>mid) change(p*2+1,mid+1,r,a,b,v);
else{
change(p*2,l,mid,a,mid,v);
change(p*2+1,mid+1,r,mid+1,b,v);
}
tree[p]=max(tree[p*2],tree[p*2+1]);
}
void brute(){
fo(i,1,n){
x[i]=read();y[i]=read();w[i]=read();
}
fo(i,1,1000)
fo(j,1,1000){
l=0;
fo(k,1,n)
if (abs(x[k]-i)+abs(y[k]-j)<=m) l+=w[k];
ans=max(ans,l);
}
printf("%d\n",ans);
}
int main(){
freopen("value.in","r",stdin);freopen("value.out","w",stdout);
n=read();m=read();
fo(i,1,n){
j=x[i]=read();k=y[i]=read();w[i]=read();
x[i]=j-k;y[i]=j+k;
add(x[i]-m+mx,i);
add(x[i]+m+mx,i);
}
fo(i,0,up){
t=h[i];
while (t){
if (t%2==1)
change(1,0,up,y[go[t]]-m+mx,y[go[t]]+m+mx,w[go[t]]);
t=nxt[t];
}
ans=max(ans,tree[1]);
t=h[i];
while (t){
if (t%2==0)
change(1,0,up,y[go[t]]-m+mx,y[go[t]]+m+mx,-w[go[t]]);
t=nxt[t];
}
}
printf("%d\n",ans);
}