JZOJ 5419. 【NOIP2017提高A组集训10.24】筹备计划

Description

题目背景

   热烈庆祝北京师范大学附属实验中学成立100周年!

问题描述

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

Input

第一行包含两个整数n,q,表示坐标的范围和发生事件的个数。
第二行包含n个整数,第i个整数ai表示在初始时刻每个位置上的学生数量。
接下来q行每行先有一个整数type。
若type=1,接下来有两个整数x,k,表示在x位置增加k名学生。
若type=2,接下来有两个整数x,k,表示在x位置减少k名学生,保证x位置一定存在至少k名学生。
若type=3,接下来有两个整数l,r,表示在[l,r]这段区间可以重新举办庆典。
若type=4,接下来有两个整数l,r,表示在[l,r]这段区间不再能举办庆典。

Output

输出总共q行,第i行的数为第i个事件发生后的答案。

Sample Input

5 4
1 0 1 0 0
1 4 1
2 3 1
4 1 3
3 2 3

Sample Output

3
1
4
2

样例说明

总共5个位置可以选择
第1个事件发生,新增加一名学生在4号位置。
第2个事件发生以前,学生分别在1,3,4位置,可以证明,在3的位置距离和最小且它是最靠左的那一个。
第2个事件发生,减少一名在3位置的学生。
第3个事件发生以前,学生分别在1,4位置,可以证明,在1的位置距离和最小且它是最靠左的那一个。
第3个事件发生,1到3号位置不能举办庆典。
第4个事件发生以前,学生分别在1,4位置,且1到3号位置不能举办庆典,可以证明,在4的位置距离和最小且它是最靠左的那一个。
第4个事件发生,2到3号位置能重新举办庆典。
最后,学生分别在1,4位置,且1号位置不能举办庆典,可以证明,在2的位置距离和最小且它是最靠左的那一个。

Data Constraint

对于20%的数据满足,n ≤ 200, q ≤ 200
对于50%的数据满足,n ≤ 2000, q ≤ 2000
对于另30%的数据满足,不存在type = 3和type = 4的操作。
对于100%的数据满足,1 ≤ n ≤ 2 ∗ 10^5, 1 ≤ q ≤ 2 ∗ 10^5, 1 ≤ k ≤ 2 ∗ 10^5, 0 ≤ ai ≤ 2 ∗ 10^5。

Solution

  • 首先我们要知道庆典肯定是在中位数处举办最好。

  • 如果一个位置已经不能举办了,那么一定是在这个位置左右最近的能举办的两个位置中其中一个。

  • 题述的四种操作都可以用线段树维护。

  • 之后二分一个位置查询这个点 x 是否为中位数(区间查询两边人数)。

  • 若单点查询 x 发现能举办,则直接输出。

  • 若不能举办,就区间查找 x 两边最近的点:

  • 具体就是区间中维护 l,r ,表示一个区间中能够达到的最近的点。

  • 再区间查询 (1,x1) r (x+1,n) l 即可。

  • 那么如何判断这两个点哪个更优呢?

  • 在线段树中维护 a[i] a[i]i ,那么前半部分答案即为: a[i]xa[i]i

  • 后半部分取相反数即可,这样就能统计出一个点作为举办位置的答案。

  • 这样的时间复杂度就是大常数的 O(N log N)

Code

#include<cstdio>
using namespace std;
const int N=2e5+2;
int n;
long long a[N];
long long num;
template<typename T>T Max(T x,T y)
{
    return x>y?x:y;
}
template<typename T>T Min(T x,T y)
{
    return x<y?x:y;
}
struct Stream
{
    inline int read()
    {
        int X=0,w=1; char ch=0;
        while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
        return X*w;
    }
    inline void write(int x)
    {
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    inline void writeln(int x)
    {
        if(x<0) x=-x,putchar('-');
        write(x),putchar('\n');
    }
}Std;
struct Segment_Tree
{
    struct data
    {
        int l,r,c;
        long long num,sum;
        bool bz;
    }f[N<<3];
    inline void update(int v)
    {
        int ls=v<<1,rs=ls|1;
        f[v].num=f[ls].num+f[rs].num;
        f[v].sum=f[ls].sum+f[rs].sum;
        f[v].bz=f[ls].bz|f[rs].bz;
        if(f[ls].bz) f[v].l=f[ls].l; else
            if(f[rs].bz) f[v].l=f[rs].l; else f[v].l=n+1;
        if(f[rs].bz) f[v].r=f[rs].r; else
            if(f[ls].bz) f[v].r=f[ls].r; else f[v].r=-1;
    }
    inline void modify(int v,int l,int r)
    {
        int ls=v<<1,rs=ls|1;
        if(f[v].c==1)
        {
            f[v].c=0;
            f[ls].c=f[rs].c=1;
            f[ls].bz=f[rs].bz=true;
            f[ls].l=l,f[rs].r=r;
            int mid=(l+r)>>1;
            f[ls].r=mid,f[rs].l=mid+1;
        }else
            if(f[v].c==2)
            {
                f[v].c=0;
                f[ls].c=f[rs].c=2;
                f[ls].bz=f[rs].bz=false;
                f[ls].l=f[rs].l=n+1;
                f[ls].r=f[rs].r=-1;
            }
    }
    inline void make(int v,int l,int r)
    {
        if(l==r)
        {
            f[v].l=f[v].r=l;
            f[v].num=a[l];
            f[v].sum=a[l]*l;
            f[v].bz=true;
            return;
        }
        int mid=(l+r)>>1;
        make(v<<1,l,mid);
        make(v<<1|1,mid+1,r);
        update(v);
    }
    inline void change_num(int v,int l,int r,int x,int y)
    {
        if(l==r)
        {
            f[v].num+=y;
            f[v].sum+=(long long)y*l;
            return;
        }
        modify(v,l,r);
        int mid=(l+r)>>1;
        if(x<=mid) change_num(v<<1,l,mid,x,y); else change_num(v<<1|1,mid+1,r,x,y);
        update(v);
    }
    inline void change_bz(int v,int l,int r,int x,int y,bool z)
    {
        if(l==x && r==y)
        {
            f[v].bz=z;
            if(z) f[v].c=1; else f[v].c=2;
            if(!z) f[v].l=n+1,f[v].r=-1; else f[v].l=l,f[v].r=r;
            return;
        }
        modify(v,l,r);
        int mid=(l+r)>>1;
        if(y<=mid) change_bz(v<<1,l,mid,x,y,z); else
            if(x>mid) change_bz(v<<1|1,mid+1,r,x,y,z); else
            {
                change_bz(v<<1,l,mid,x,mid,z);
                change_bz(v<<1|1,mid+1,r,mid+1,y,z);
            }
        update(v);
    }
    inline long long find_num(int v,int l,int r,int x,int y)
    {
        if(l>=x && r<=y) return f[v].num;
        int mid=(l+r)>>1;
        if(y<=mid) return find_num(v<<1,l,mid,x,y);
        if(x>mid) return find_num(v<<1|1,mid+1,r,x,y);
        return find_num(v<<1,l,mid,x,mid)+find_num(v<<1|1,mid+1,r,mid+1,y);
    }
    inline long long find_sum(int v,int l,int r,int x,int y)
    {
        if(l>=x && r<=y) return f[v].sum;
        int mid=(l+r)>>1;
        if(y<=mid) return find_sum(v<<1,l,mid,x,y);
        if(x>mid) return find_sum(v<<1|1,mid+1,r,x,y);
        return find_sum(v<<1,l,mid,x,mid)+find_sum(v<<1|1,mid+1,r,mid+1,y);
    }
    inline bool find_bz(int v,int l,int r,int x)
    {
        modify(v,l,r);
        if(l==r) return f[v].bz;
        int mid=(l+r)>>1;
        bool bz=x<=mid?find_bz(v<<1,l,mid,x):find_bz(v<<1|1,mid+1,r,x);
        update(v);
        return bz;
    }
    inline int findl(int v,int l,int r,int x,int y)
    {
        modify(v,l,r);
        if(l>=x && r<=y)
        {
            if(!f[v].bz) return -1;
            return f[v].r;
        }
        int mid=(l+r)>>1;
        if(y<=mid) return findl(v<<1,l,mid,x,y);
        if(x>mid) return findl(v<<1|1,mid+1,r,x,y);
        return Max<int>(findl(v<<1,l,mid,x,mid),findl(v<<1|1,mid+1,r,mid+1,y));
    }
    inline int findr(int v,int l,int r,int x,int y)
    {
        modify(v,l,r);
        if(l>=x && r<=y)
        {
            if(!f[v].bz) return n+1;
            return f[v].l;
        }
        int mid=(l+r)>>1;
        if(y<=mid) return findr(v<<1,l,mid,x,y);
        if(x>mid) return findr(v<<1|1,mid+1,r,x,y);
        return Min<int>(findr(v<<1,l,mid,x,mid),findr(v<<1|1,mid+1,r,mid+1,y));
    }
    inline long long calc(int x)
    {
        long long y=0;
        if(x>1) y=find_num(1,1,n,1,x-1)*x-find_sum(1,1,n,1,x-1);
        if(x<n) y+=find_sum(1,1,n,x+1,n)-find_num(1,1,n,x+1,n)*x;
        return y;
    }
}Tree;
int main()
{
    n=Std.read();int q=Std.read();
    for(int i=1;i<=n;i++) num+=a[i]=Std.read();
    Tree.make(1,1,n);
    while(q--)
    {
        int type=Std.read(),x=Std.read(),y=Std.read();
        if(type==1) Tree.change_num(1,1,n,x,y),num+=y;
        if(type==2) Tree.change_num(1,1,n,x,-y),num-=y;
        if(type==3) Tree.change_bz(1,1,n,x,y,true);
        if(type==4) Tree.change_bz(1,1,n,x,y,false);
        int l=1,r=n,ans=0;
        long long sl=0,sr=0,midnum=(num+1)>>1;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            long long z=Tree.find_num(1,1,n,l,mid);
            if(sl+z<midnum) ans=mid,l=mid+1,sl+=z; else r=mid-1,sr+=num-sr-sl-z;
        }
        if(Tree.find_bz(1,1,n,++ans))
        {
            Std.writeln(ans);
            continue;
        }
        int ans1=ans>1?Tree.findl(1,1,n,1,ans-1):-1;
        int ans2=ans<n?Tree.findr(1,1,n,ans+1,n):n+1;
        if((ans1<0 || ans1>n) && (ans2<0 || ans2>n))
        {
            Std.writeln(-1);
            continue;
        }
        int node=ans1;
        if((ans1<0 || ans1>n) || ans2>0 && ans2<=n && Tree.calc(ans1)>Tree.calc(ans2)) node=ans2;
        Std.writeln(node);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值