【JZOJ5419】筹备计划
Description
题目背景
热烈庆祝北京师范大学附属实验中学成立100周年!
问题描述
校庆筹备组的老师们正在寻找合适的地方来举办校庆庆典。
学生们的位置和可以举办庆典的位置在x轴的正半轴取值在[1,n]的整数位置上。
老师们选择的地点是会根据参加典礼的学生位置来决定的,具体来说:定义一个位置的距离和为该位置到所有参加学生的距离之和。如果一个位置的距离和最小,且它比所有和它距离和相等的位置的位置更靠左,则老师们会选择这个位置。
开始时,所有的位置都可以举办庆典。但很可惜的是,并不是所有的位置都能举办庆典,有些奇怪的事件会使[l,r]这段区间不能举办庆典,不过有时也会使[l,r]可以重新举办庆典(并不保证[l,r]之前的每个位置都不能举办庆典)。
有时一些学生会因为某些原因不能参加庆典,有时一些学生会主动报名参加庆典。
作为一名合格的老师,你需要求出每个事件发生后庆典应该选择的位置,如果没有合法位置,请输出-1。
Solution
记
Si
为所有学生到
i
的距离和,
那么这个 di 是单调的,即 Si 是呈单峰图像的。
当没有type=3或4时,选择的即最后一个 di<0 的位置,记它为 pos 。
考虑区间被覆盖,那么一定是 pos 往左第一个可行点和往右第一个可行点,比较一下他们的距离和就可以判断哪个位置更优。
这些都可以用线段树维护。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 200010
#define inf 21474836470000000ll
#define ll long long
using namespace std;
struct node{
int rp,lp;
ll d,lz,x;
int fg;
}tr[N*4];
int n;
int min(int x,int y){
return x<y?x:y;
}
int max(int x,int y){
return x>y?x:y;
}
ll minll(ll x,ll y){
return x<y?x:y;
}
void down(int v,int l,int r){
int mid=(l+r)/2;
if(tr[v].fg>=0){
int z=tr[v].fg;
if(z==1){
tr[v*2].rp=0,tr[v*2].lp=n+1;
tr[v*2+1].rp=0,tr[v*2+1].lp=n+1;
}
else{
tr[v*2].rp=mid,tr[v*2].lp=l;
tr[v*2+1].rp=r,tr[v*2+1].lp=mid+1;
}
tr[v*2].fg=tr[v*2+1].fg=z,tr[v].fg=-1;
}
if(!tr[v].lz) return;
ll z=tr[v].lz;
tr[v*2].d+=z*(mid-l+1),tr[v*2+1].d+=z*(r-mid);
tr[v*2].lz+=z,tr[v*2+1].lz+=z;
tr[v*2].x+=z,tr[v*2+1].x+=z;
tr[v].lz=0;
}
void uppos(int v){
tr[v].rp=max(tr[v*2].rp,tr[v*2+1].rp);
tr[v].lp=min(tr[v*2].lp,tr[v*2+1].lp);
}
void upd(int v){
tr[v].d=tr[v*2].d+tr[v*2+1].d;
tr[v].x=minll(tr[v*2].x,tr[v*2+1].x);
}
void build(int v,int l,int r){
tr[v].fg=-1;
if(l==r) {tr[v].lp=tr[v].rp=l;return;}
int mid=(l+r)/2;
build(v*2,l,mid),build(v*2+1,mid+1,r);
uppos(v),upd(v);
}
int get(int v,int l,int r,int x,int y,int t){
if(l==x && r==y){
return t?tr[v].rp:tr[v].lp;
}
down(v,l,r);
int mid=(l+r)/2;
if(y<=mid) return get(v*2,l,mid,x,y,t);
else if(x>mid) return get(v*2+1,mid+1,r,x,y,t);
else{
int p=get(v*2,l,mid,x,mid,t),q=get(v*2+1,mid+1,r,mid+1,y,t);
return t?max(p,q):min(p,q);
}
}
ll sum(int v,int l,int r,int x,int y){
if(l==x && r==y){
return tr[v].d;
}
down(v,l,r);
int mid=(l+r)/2;
if(y<=mid) return sum(v*2,l,mid,x,y);
else if(x>mid) return sum(v*2+1,mid+1,r,x,y);
else return sum(v*2,l,mid,x,mid)+sum(v*2+1,mid+1,r,mid+1,y);
}
void add(int v,int l,int r,int x,int y,int t){
if(l==x && r==y){
tr[v].d+=(ll)t*(r-l+1),tr[v].x+=t,tr[v].lz+=t;
return;
}
down(v,l,r);
int mid=(l+r)/2;
if(y<=mid) add(v*2,l,mid,x,y,t);
else if(x>mid) add(v*2+1,mid+1,r,x,y,t);
else add(v*2,l,mid,x,mid,t),add(v*2+1,mid+1,r,mid+1,y,t);
upd(v);
}
void modify(int v,int l,int r,int x,int y,int t){
if(l==x && r==y){
tr[v].fg=t;
if(!t) tr[v].rp=r,tr[v].lp=l;
else tr[v].rp=0,tr[v].lp=n+1;
return;
}
down(v,l,r);
int mid=(l+r)/2;
if(y<=mid) modify(v*2,l,mid,x,y,t);
else if(x>mid) modify(v*2+1,mid+1,r,x,y,t);
else modify(v*2,l,mid,x,mid,t),modify(v*2+1,mid+1,r,mid+1,y,t);
uppos(v);
}
int find(int v,int l,int r){
if(l==r) return l;
down(v,l,r);
int mid=(l+r)/2;
if(tr[v*2+1].x<0) return find(v*2+1,mid+1,r);
else return find(v*2,l,mid);
}
void put(int x,int t){
add(1,1,n,1,x,-t);
if(x<n) add(1,1,n,x+1,n,t);
}
int main()
{
freopen("position.in","r",stdin);
freopen("position.out","w",stdout);
int q,o;
scanf("%d %d",&n,&q);
build(1,1,n);
fo(i,1,n) scanf("%d",&o),put(i,o);
while(q--)
{
int type,x,y;
scanf("%d %d %d",&type,&x,&y);
if(type==1) put(x,y);
else if(type==2) put(x,-y);
else if(type==3) modify(1,1,n,x,y,0);
else modify(1,1,n,x,y,1);
int p=find(1,1,n);
ll tmp=inf,ans=-1;
int lp=get(1,1,n,p,n,0),rp=get(1,1,n,1,p,1);
if(rp){
ll t=sum(1,1,n,1,rp);
if(tmp>t) tmp=t,ans=rp;
}
if(lp<=n){
ll t=sum(1,1,n,1,lp);
if(tmp>t) tmp=t,ans=lp;
}
printf("%d\n",ans);
}
}