很烦人的线段树= =。不过理解了以后还是挺好打的,就是太长。
具体的话就是维护每一个区间内到左端点右端点的最小代价和最左边,最右边的可用的位置,然后直接更新就好了,至于查询的话,就是查询中位数咯,查询一下中位数左右两边最靠近他的可用的点,然后取个代价最小的。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=2e5+5;
typedef long long ll;
const ll inf=1e17;
int n,m,a[N];
struct tree
{
int lb,rb,lazy,sb;
ll tol,tor,s;
}t[N*5];
struct node
{
int x;
ll y;
};
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void pushup(int x,int l,int r)
{
int mid=(l+r)>>1;
t[x].lb=t[x<<1].lb?t[x<<1].lb:t[x<<1|1].lb;
t[x].rb=t[x<<1|1].rb?t[x<<1|1].rb:t[x<<1].rb;
t[x].sb=t[x<<1].sb+t[x<<1|1].sb;
t[x].s=t[x<<1].s+t[x<<1|1].s;
t[x].tol=t[x<<1].tol+t[x<<1|1].tol+1ll*t[x<<1|1].s*(mid-l+1);
t[x].tor=t[x<<1|1].tor+t[x<<1].tor+1ll*t[x<<1].s*(r-mid);
}
inline void pushdown(int x,int l,int r)
{
if (l==r||t[x].lazy==-1) return;
int lazy=t[x].lazy;
int mid=(l+r)>>1;
t[x].lazy=-1;
if (!lazy)
{
t[x<<1].lazy=t[x<<1|1].lazy=lazy;
t[x<<1].lb=l;
t[x<<1].rb=mid;
t[x<<1].sb=mid-l+1;
t[x<<1|1].lb=mid+1;
t[x<<1|1].rb=r;
t[x<<1|1].sb=r-mid;
}
else
{
t[x<<1].lazy=t[x<<1|1].lazy=lazy;
t[x<<1].lb=t[x<<1].rb=t[x<<1].sb=0;
t[x<<1|1].lb=t[x<<1|1].rb=t[x<<1|1].sb=0;
}
}
inline void build(int x,int l,int r)
{
if (l==r)
{
t[x].s=a[l];
t[x].rb=t[x].lb=l;
t[x].sb=1,t[x].lazy=-1;
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x,l,r);
}
inline void ins(int x,int l,int r,int pos,int v)
{
pushdown(x,l,r);
if (l==r)
{
t[x].s+=1ll*v;
return;
}
int mid=(l+r)>>1;
if (pos<=mid)ins(x<<1,l,mid,pos,v);
else ins(x<<1|1,mid+1,r,pos,v);
pushup(x,l,r);
}
inline void change(int x,int l,int r,int l1,int r1,int ok)
{
//if (l1>r1)return;
if (l==l1&&r==r1)
{
t[x].lazy=ok;
if (!ok)t[x].lb=l,t[x].rb=r,t[x].sb=r-l+1;
else t[x].lb=t[x].rb=t[x].sb=0;
return;
}pushdown(x,l,r);
int mid=(l+r)>>1;
if (r1<=mid)change(x<<1,l,mid,l1,r1,ok);
else if (l1>mid)change(x<<1|1,mid+1,r,l1,r1,ok);
else
{
change(x<<1,l,mid,l1,mid,ok);
change(x<<1|1,mid+1,r,mid+1,r1,ok);
}
//change(x<<1,l,mid,l1,min(r1,mid),ok);
//change(x<<1|1,mid+1,r,max(l1,mid+1),r1,ok);
pushup(x,l,r);
}
inline int query(int x,int l,int r,ll kth)
{
if (l==r)return l;
int mid=(l+r)>>1;
if (t[x<<1].s>=kth)return query(x<<1,l,mid,kth);
else return query(x<<1|1,mid+1,r,kth-t[x<<1].s);
}
node getlb(int x,int l,int r,int l1,int r1)
{
node ans;
if (!t[x].sb||l1>r1)return ans=(node){0,inf};
pushdown(x,l,r);
if (l==r)return ans=(node){l,0};
int mid=(l+r)>>1;
if (t[x<<1].rb&&t[x<<1].rb>=l1)
{
node ans=getlb(x<<1,l,mid,l1,min(mid,r1));
if (ans.x)
ans.y+=t[x<<1|1].tol+1ll*t[x<<1|1].s*(mid-ans.x+1);
return ans;
}
else
{
node ans=getlb(x<<1|1,mid+1,r,max(l1,mid+1),r1);
if (ans.x)
ans.y+=t[x<<1].tor+1ll*t[x<<1].s*(ans.x-mid);
return ans;
}
}
node getrb(int x,int l,int r,int l1,int r1)
{
node ans;
if (!t[x].sb||l1>r1)return ans=(node){0,inf};
pushdown(x,l,r);
if (l==r)return ans=(node){l,0};
int mid=(l+r)>>1;
if (t[x<<1|1].lb&&t[x<<1|1].lb<=r1)
{
node ans=getrb(x<<1|1,mid+1,r,max(l1,mid+1),r1);
if (ans.x)
ans.y+=t[x<<1].tor+1ll*t[x<<1].s*(ans.x-mid);
return ans;
}
else
{
node ans=getrb(x<<1,l,mid,l1,min(mid,r1));
if (ans.x)
ans.y+=t[x<<1|1].tol+1ll*t[x<<1|1].s*(mid-ans.x+1);
return ans;
}
}
int main()
{
freopen("position.in","r",stdin);
freopen("position.out","w",stdout);
n=read(),m=read();
ll tot=0;
fo(i,1,n)a[i]=read(),tot+=a[i];
build(1,1,n);
while(m--)
{
int op=read(),x=read(),y=read();
if (op==1)ins(1,1,n,x,y),tot+=y;
if (op==2)ins(1,1,n,x,-y),tot-=y;
if (op==3)change(1,1,n,x,y,0);
if (op==4)change(1,1,n,x,y,1);
int mid=query(1,1,n,(tot+1)/2);
node l=getrb(1,1,n,1,mid);
node r=getlb(1,1,n,mid,n);
if (!l.x&&!r.x)printf("-1\n");
else
{
if (l.y<=r.y)printf("%d\n",l.x);
else printf("%d\n",r.x);
}
}
}