正题
题目链接:http://noip.ybtoj.com.cn/contest/90/problem/4
题目大意
一个集合[1,n]∈S[1,n]\in S[1,n]∈S,和一个序列aaa。有操作
- 序列aaa的一个数加上xxx
- 序列aaa的一个数减去xxx
- 将[l,r][l,r][l,r]加入集合SSS
- 将[l,r][l,r][l,r]删除出集合SSS
每次修改后求一个k∈Sk\in Sk∈S使得∑i=1∣i−k∣ai\sum_{i=1}|i-k|a_ii=1∑∣i−k∣ai最小
解题思路
如果不考虑集合SSS来选数那么一定是选序列aia_iai的带权中位数(((即有aia_iai个iii)))。
那么考虑上集合SSS一定是选择离SSS近的,我们直接找到左右两边最近的值然后用树状数组判断答案大小即可。
时间复杂度O(nlogn)O(n\log n)O(nlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&-x)
#define ll long long
using namespace std;
const ll N=2e5+10;
ll n,q;
struct Seq_Tree{ll s[N*4],lazy[N*4],w[N*4];void Downdata(ll x,ll l,ll mid,ll r){if(!lazy[x])return;lazy[x*2]=lazy[x*2+1]=lazy[x];lazy[x]--;s[x*2]=(mid-l+1)*lazy[x];s[x*2+1]=(r-mid)*lazy[x];lazy[x]=0;return;}void Cover(ll x,ll L,ll R,ll l,ll r,ll val){if(L==l&&R==r){s[x]=(R-L+1)*val;lazy[x]=val+1;return;}ll mid=(L+R)>>1;Downdata(x,L,mid,R);if(r<=mid)Cover(x*2,L,mid,l,r,val);else if(l>mid)Cover(x*2+1,mid+1,R,l,r,val);else Cover(x*2,L,mid,l,mid,val),Cover(x*2+1,mid+1,R,mid+1,r,val);s[x]=s[x*2]+s[x*2+1];w[x]=w[x*2]+w[x*2+1];return;}void Change(ll x,ll L,ll R,ll pos,ll val){if(L==R){w[x]+=val;return;}ll mid=(L+R)>>1;Downdata(x,L,mid,R);if(pos<=mid)Change(x*2,L,mid,pos,val);else Change(x*2+1,mid+1,R,pos,val);s[x]=s[x*2]+s[x*2+1];w[x]=w[x*2]+w[x*2+1];}ll Find(ll x,ll L,ll R,ll k){if(L==R)return s[x];ll mid=(L+R)>>1;Downdata(x,L,mid,R);if(w[x*2]>=k)return Find(x*2,L,mid,k);return s[x*2]+Find(x*2+1,mid+1,R,k-w[x*2]);}ll Ask(ll x,ll L,ll R,ll k){if(L==R)return L;ll mid=(L+R)>>1;Downdata(x,L,mid,R);if(s[x*2]>=k)return Ask(x*2,L,mid,k);return Ask(x*2+1,mid+1,R,k-s[x*2]);}
}T;
struct BIT{ll t[N],w[N];void Change(ll x,ll val){ll k=n-x+1;while(x<=n){t[x]+=val*k;w[x]+=val;x+=lowbit(x); }return;}ll Ask(ll x){ll ans=0,k=n-x+1;while(x){ans+=t[x]-w[x]*k;x-=lowbit(x);}return ans;}
}Tl,Tr;
ll check(ll x)
{return Tl.Ask(x)+Tr.Ask(n-x+1);}
void updata(ll x,ll w){Tl.Change(x,w);Tr.Change(n-x+1,w);return;
}
int main()
{freopen("position.in","r",stdin);freopen("position.out","w",stdout);scanf("%lld%lld",&n,&q);for(ll i=1;i<=n;i++){ll x;scanf("%lld",&x);T.Change(1,0,n+1,i,x);Tl.Change(i,x);Tr.Change(n-i+1,x);}T.Cover(1,0,n+1,0,n+1,1);while(q--){ll op,x,y;scanf("%lld%lld%lld",&op,&x,&y);if(op==1)T.Change(1,0,n+1,x,y),updata(x,y); if(op==2)T.Change(1,0,n+1,x,-y),updata(x,-y);if(op==3)T.Cover(1,0,n+1,x,y,1);if(op==4)T.Cover(1,0,n+1,x,y,0);ll k=T.Find(1,0,n+1,(T.w[1]+1)/2);x=T.Ask(1,0,n+1,k);y=T.Ask(1,0,n+1,k+1);if(!x&&y==n+1)printf("-1\n");else if(!x)printf("%lld\n",y);else if(y==n+1)printf("%lld\n",x);else if(check(x)<=check(y))printf("%lld\n",x);else printf("%lld\n",y);}
}