人生的价值

题目大意

一堆二维点,有点权。
选择一个坐标建饭堂可以收获所有与其曼哈顿距离不超过m的点的点权。
求最大收获。

切比雪夫距离

曼哈顿距离是个菱形。
将坐标轴旋转45度,再进行放缩,转化为图像是正方形的切比雪夫距离。
然后可以经典扫描线。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值