【jzoj4898】【人生的价值】【扫描线】【线段树】

题目大意

YYHS的校园可以抽象成一个无限二维平面,校园里分布着N个教室(编号为1..N),第i个教室的坐标为(x[i], y[i]),里面有w[i]个学生。新食堂的饭菜十分美味,然而同学们都比较懒。当且仅当新食堂的位置和第i个教室的位置的曼哈顿距离小于等于L,第i个教室里的学生会去新食堂吃饭。有博爱之心的NiroBC希望有尽量多的学生去新食堂吃饭,那么这个问题就交给你了!

解题思路

通过观察可以发现,有一些正方形,求一个点是包含它的正方形的价值和最大。首先以直线y=x为横轴,y=-x为纵轴建立平面直角坐标系,接着就可以用扫描线做,把一个正方形拆成添加和删除两个操作,用线段树维护最大值,修改区间加减。

code

#include<cmath>
#include<cstdio>
#include<algorithm>
#define LD double
#define LL long long
#define min(x,y) ((x<y)?x:y)
#define max(x,y) ((x>y)?x:y)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=1e5;
int n,l,c[maxn*2+10],mx[maxn*8+10],tag[maxn*8+10];
LD b[maxn*2+10];
bool cmp(LD x,LD y){
    return x+1e-10<y;
}
struct rec{
    LD x,ly,ry;int op;
};
rec a[maxn*2+10];
bool cmp2(rec x,rec y){
    return (x.x+1e-10<y.x)||((x.x<1e-10+y.x)&&(x.x+1e-10>y.x)&&(x.op>y.op));
}
void retag(int pos){
    tag[pos*2]+=tag[pos];tag[pos*2+1]+=tag[pos];
    mx[pos*2]+=tag[pos];mx[pos*2+1]+=tag[pos];
    tag[pos]=0;
}
int qury(int pos,int l,int r,int ll,int rr){
    int mid=(l+r)/2;
    if(l!=r)retag(pos);
    if((l==ll)&&(r==rr))return mx[pos];
    else if(rr<=mid)return qury(pos*2,l,mid,ll,rr);
    else if(mid<ll)return qury(pos*2+1,mid+1,r,ll,rr);
    else return max(qury(pos*2,l,mid,ll,mid),qury(pos*2+1,mid+1,r,mid+1,rr));
}
void add(int pos,int l,int r,int ll,int rr,int val){
    int mid=(l+r)/2;
    if(l!=r)retag(pos);
    if((l==ll)&&(r==rr)){
        tag[pos]=val;
        mx[pos]+=val;
        return;
    }else if(rr<=mid)add(pos*2,l,mid,ll,rr,val);
    else if(mid<ll)add(pos*2+1,mid+1,r,ll,rr,val);
    else{add(pos*2,l,mid,ll,mid,val);add(pos*2+1,mid+1,r,mid+1,rr,val);}
    mx[pos]=max(mx[pos*2],mx[pos*2+1]);
}
int main(){
    freopen("value.in","r",stdin);
    freopen("value.out","w",stdout);
    scanf("%d%d",&n,&l);
    LD sqrt2=sqrt(2),R=l/sqrt2;
    int cnt=0,cnt2=0;
    fo(i,1,n){
        int x,y,w;scanf("%d%d%d",&x,&y,&w);
        LD xx=sqrt2*x+((y>x)?(y-x)/sqrt2:-(x-y)/sqrt2),
           yy=((y>x)?(y-x)/sqrt2:-(x-y)/sqrt2);
        a[++cnt].x=xx-R;a[cnt].ly=yy-R;a[cnt].ry=yy+R;a[cnt].op=w;
        a[++cnt].x=xx+R;a[cnt].ly=yy-R;a[cnt].ry=yy+R;a[cnt].op=-w;
        b[++cnt2]=yy-R;b[++cnt2]=yy+R;
    }
    sort(b+1,b+cnt2+1,cmp);
    c[1]=1;fo(i,2,cnt2)c[i]=c[i-1]+(b[i-1]+1e-10<b[i]);
    fo(i,1,cnt){
        int l=1,r=cnt2;
        for(;l!=r;){
            int mid=(l+r)/2;
            if(b[mid]+1e-10<a[i].ly)l=mid+1;
            else r=mid;
        }
        a[i].ly=c[l];
        l=1,r=cnt2;
        for(;l!=r;){
            int mid=(l+r)/2;
            if(b[mid]+1e-10<a[i].ry)l=mid+1;
            else r=mid;
        }
        a[i].ry=c[l];
    }
    sort(a+1,a+cnt+1,cmp2);
    int ans=0;
    fo(i,1,cnt){
        if(a[i].op<0)ans=max(ans,qury(1,1,c[cnt2],a[i].ly,a[i].ry));
        add(1,1,c[cnt2],a[i].ly,a[i].ry,a[i].op);
    }
    printf("%d",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值