JZOJ 4898 人生的价值(线段树、扫描线)

3 篇文章 0 订阅
1 篇文章 0 订阅

题目大意

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

n<=100,000,x,y,l<=100000
时间限制 1s
空间限制 256M

解题思路

经典扫描线。只不过要变换一下坐标,对于每一件教室,能让学生去新食堂的食堂位置的范围是一个以教室为中心的菱形,我们只需要这样:
把教室坐标(x,y)变成(x-y,x+y),这样这个菱形就可以转化成正方形。
然后把这些正方形的左右对边分别取出来,混在一起排序。
之后从1~n+n扫描这些边,遇到正方形的左边就在线段树上纵坐标对应的区间上加上w,遇到右边就减去w。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100006
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;

struct node
{
    int x,y;
} a[maxn];
struct nod
{
    int x,z,st,en,w;
} l[maxn+maxn];
bool cmp(nod a,nod b)
{
    return a.x<b.x || a.x==b.x && a.z<b.z;
}
int i,n,lll,x,y,w,tot,s,ans,mx,tr[maxn*8],c[maxn*8];
void update(int v,int st,int en)
{
    if (!c[v]) return;
    tr[v+v]+=c[v],tr[v+v+1]+=c[v];
    c[v+v]+=c[v],c[v+v+1]+=c[v];
    c[v]=0;
    return;
}
void modify(int v,int st,int en,int l,int r,int x)
{
    if (st==l && en==r)
    {
        tr[v]+=x;
        c[v]+=x;
        return;
    }
    update(v,st,en);
    int m=(st+en) >> 1;
    if (r<=m) modify(v+v,st,m,l,r,x);
    else if (l>m) modify(v+v+1,m+1,en,l,r,x);
    else
    {
        modify(v+v,st,m,l,m,x);
        modify(v+v+1,m+1,en,m+1,r,x);
    }
    tr[v]=max(tr[v+v],tr[v+v+1]);
    return;
}
void findd(int v,int st,int en,int l,int r)
{
    if (st==l && en==r)
    {
        s=max(s,tr[v]);
        return;
    }
    update(v,st,en);
    int m=(st+en) >> 1;
    if (r<=m) findd(v+v,st,m,l,r);
    else if (l>m) findd(v+v+1,m+1,en,l,r);
    else
    {
        findd(v+v,st,m,l,m);
        findd(v+v+1,m+1,en,m+1,r);
    }
    return;
}
int main()
{
    freopen("value.in","r",stdin);
    freopen("value.out","w",stdout);
    scanf("%d%d",&n,&lll);
    fr(i,1,n)
    {
        scanf("%d%d%d",&x,&y,&w);
        a[i].x=x-y,a[i].y=x+y;
        l[i].x=a[i].x-lll,l[i].st=a[i].y-lll,l[i].en=a[i].y+lll,l[i].z=0,l[i].w=w;
        l[i+n].x=a[i].x+lll,l[i+n].st=a[i].y-lll,l[i+n].en=a[i].y+lll,l[i+n].z=1,l[i+n].w=w;
        l[i].st=max(l[i].st,1),l[i+n].st=max(l[i+n].st,1);
        l[i].en=max(l[i].en,1),l[i+n].en=max(l[i+n].en,1);
        mx=max(mx,a[i].y+lll);
    }
    tot=n+n;
    sort(l+1,l+tot+1,cmp);
    fr(i,1,tot)
    {
        if (l[i].z==0) modify(1,1,mx,l[i].st,l[i].en,l[i].w);
        s=0;
        findd(1,1,mx,l[i].st,l[i].en);
        ans=max(ans,s);
        if (l[i].z==1) modify(1,1,mx,l[i].st,l[i].en,-l[i].w);
    }
    printf("%d\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值