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,x−1) 的 r 和
(x+1,n) 的 l 即可。那么如何判断这两个点哪个更优呢?
在线段树中维护
a[i] 和 a[i]∗i ,那么前半部分答案即为: a[i]∗x−a[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;
}