您的位置:首页 > 其它

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

2016-11-16 20:53 288 查看

题目大意

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  扫描线