Description
校庆筹备组的老师们正在寻找合适的地方来举办校庆庆典。
学生们的位置和可以举办庆典的位置在x轴的正半轴取值在[1,n]的整数位置上。
老师们选择的地点是会根据参加典礼的学生位置来决定的,具体来说:定义一个位置的距离和为该位置到所有参加学生的距离之和。如果一个位置的距离和最小,且它比所有和它距离和相等的位置的位置更靠左,则老师们会选择这个位置。
开始时,所有的位置都可以举办庆典。但很可惜的是,并不是所有的位置都能举办庆典,有些奇怪的事件会使[l,r]这段区间不能举办庆典,不过有时也会使[l,r]可以重新举办庆典(并不保证[l,r]之前的每个位置都不能举办庆典)。
有时一些学生会因为某些原因不能参加庆典,有时一些学生会主动报名参加庆典。
作为一名合格的老师,你需要求出每个事件发生后庆典应该选择的位置,如果没有合法位置,请输出-1。
Solution
考虑一个位置成为最有的情况是什么:它往左移不会优,右移不会优,
那么也就是(sum为a的前缀和)
sumi>=All−sumi
,
All−sumi−1>=sumi−1
移项:
2sumi>=All
,
2sumi−1<=All
所以找到最左的一个位置i,使得
2sumi>=All
即可,
那加入有些位置不能选怎么做?
显然,加入这个限制后的答案,一定是不加限制的最优位置的尽量左边或尽量右边,
那就先找出不加限制的最优位置,
再找出这个位置的左边第一个个可以选的,右边第一个可以选的,看看哪个优一点,
复杂度:
O(nlog(n)2)
用线段树找不加限制的最优位置可以优化成:
O(nlog(n))
Code
#include <cstdio>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
#define NX(q) ((q)&(-(q)))
using namespace std;
typedef long long LL;
const int N=200500;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans;
LL ans1;
LL a[N];
bool z[N];
LL ALLl,ALLr,ALLn;
LL sum[3][N];
struct qqww
{
int v,la;
}b[N*4];
void ADD(int q,LL w,int E){for(;q<=n;q+=NX(q))sum[E][q]+=w;}
void JIA(int i,LL w){ALLn+=w,ALLl+=w*(LL)i,ALLr+=w*(LL)(n-i);ADD(i,w,0),ADD(i,w*(LL)i,1),ADD(i,w*(LL)(n-i),2);}
LL Gsum(int q,int E)
{
LL ans=0;if(q>n)q=n;
for(;q>0;q-=NX(q))ans+=sum[E][q];
return ans;
}
void doit(int l,int r,int e)
{
if(!b[e].la)return;
b[e].v=(b[e].la-1)*(r-l+1);
if(l!=r)b[e*2].la=b[e*2+1].la=b[e].la;
b[e].la=0;
}
void change(int l,int r,int e,int l1,int r1,int l2)
{
int t=(l+r)>>1;if(l!=r)doit(l,t,e*2),doit(t+1,r,e*2+1);
if(l1<=l&&r<=r1){b[e].la=l2,doit(l,r,e);return;}
if(r1<=t)change(l,t,e*2,l1,r1,l2);
else if(t<l1)change(t+1,r,e*2+1,l1,r1,l2);
else change(l,t,e*2,l1,t,l2),change(t+1,r,e*2+1,t+1,r1,l2);
b[e].v=b[e*2].v+b[e*2+1].v;
}
int findl(int l,int r,int e,int r1)
{
if(b[e].v==r-l+1)return -1;
if(l==r)return l;
int t=(l+r)>>1;if(l!=r)doit(l,t,e*2),doit(t+1,r,e*2+1);
if(r1<=t)findl(l,t,e*2,r1);
else
{
int ans=findl(t+1,r,e*2+1,r1);
return ans!=-1?ans:findl(l,t,e*2,r1);
}
}
int findr(int l,int r,int e,int l1)
{
if(b[e].v==r-l+1)return -1;
if(l==r)return l;
int t=(l+r)>>1;if(l!=r)doit(l,t,e*2),doit(t+1,r,e*2+1);
if(t<l1)findr(t+1,r,e*2+1,l1);
else
{
int ans=findr(l,t,e*2,l1);
return ans!=-1?ans:findr(t+1,r,e*2+1,l1);
}
}
int EF(int l,int r)
{
for(;l<r;)
{
int mid=(l+r)>>1;
if(2LL*Gsum(mid,0)>=ALLn)r=mid;
else l=mid+1;
}
return r;
}
LL JS(LL q)
{
LL t=Gsum(q,0);
LL ans=Gsum(q,2)-t*(LL)(n-q);
ans+=ALLl-Gsum(q,1)-(LL)(ALLn-t)*(q);
return ans;
}
int main()
{
freopen("position.in","r",stdin);
freopen("position.out","w",stdout);
int q,w,e;
read(n),read(m);
fo(i,1,n)JIA(i,read(q));
LL t;
ans=EF(1,n);
fo(I,1,m)
{
read(e);read(q),read(w);
if(e==1)JIA(q,w);
else if(e==2)JIA(q,-w);
else if(e==3)change(1,n,1,q,w,1);
else change(1,n,1,q,w,2);
ans=EF(1,n);
q=findl(1,n,1,ans);
w=findr(1,n,1,ans);
if(q==w&&q==-1){printf("-1\n");continue;}
if(q==-1){printf("%d\n",w);continue;}
if(w==-1){printf("%d\n",q);continue;}
if(JS(w)<JS(q))printf("%d\n",w);
else printf("%d\n",q);
}
return 0;
}