【JZOJ5419】筹备计划

Description

题目背景
热烈庆祝北京师范大学附属实验中学成立100周年!
问题描述
校庆筹备组的老师们正在寻找合适的地方来举办校庆庆典。
学生们的位置和可以举办庆典的位置在x轴的正半轴取值在[1,n]的整数位置上。
老师们选择的地点是会根据参加典礼的学生位置来决定的,具体来说:定义一个位置的距离和为该位置到所有参加学生的距离之和。如果一个位置的距离和最小,且它比所有和它距离和相等的位置的位置更靠左,则老师们会选择这个位置。
开始时,所有的位置都可以举办庆典。但很可惜的是,并不是所有的位置都能举办庆典,有些奇怪的事件会使[l,r]这段区间不能举办庆典,不过有时也会使[l,r]可以重新举办庆典(并不保证[l,r]之前的每个位置都不能举办庆典)。
有时一些学生会因为某些原因不能参加庆典,有时一些学生会主动报名参加庆典。
作为一名合格的老师,你需要求出每个事件发生后庆典应该选择的位置,如果没有合法位置,请输出-1。

Solution

Si 为所有学生到 i 的距离和,di SiSi1 ,如果在 p 位置增加了一个学生,那么会使d1~ di 全部减一, di+1 ~ dn 全部加一。

那么这个 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);
    }
}
posted @ 2017-10-24 22:27  sadstone  阅读(42)  评论(0编辑  收藏  举报