樹狀數組 二分
題目大意: 維護一個數列,每次操作爲先修改一個數,再詢問是否存在一個位置滿足並輸出這個位置。
妙蛙
問題要求出滿足 的位置,這個可以轉化爲
我們考慮從 開始跳,每一次跳到其後面一個最小的 ,滿足
可以證明如果有答案且 ,那麼答案一定在所有的 之中產生
不妨用反證法來證明,假設當且跳到點 ,接下來選取的點是 ,對於
如果說 是答案的話,設 爲 第一個滿足 的點。
因爲 所以必然有 ,如果 那麼 ,i 不是答案
所以證明了這樣跳,如果有答案的話答案必然在跳到的點上
所以可以用樹狀數組維護前綴和,每一次暴力二分跳,跳 次就能跳完,總複雜度是
------Mangoyang
代碼:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define F inline
using namespace std;
typedef long long LL;
int n,q,a[N]; LL t[N];
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
return l==r?EOF:*l++;
}
F int _read(){
int x=0; char ch=readc();
while (!isdigit(ch)) ch=readc();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x;
}
F void mdfy(int x,LL w){ for (;x<=n;x+=x&-x) t[x]+=w; }
F LL srch(int x){ LL s=0; for (;x;x-=x&-x) s+=t[x]; return s; }
F int pd(int x){
int l=x+1,r=n,ans=x,mid; LL s=srch(x)<<1;
while (l<=r)
if (srch(mid=l+r>>1)<s) ans=mid,l=mid+1;
else r=mid-1;
return ans;
}
F int calc(){
if (!t[1]) return 1;
for (int x=1;x<n;x=max(x+1,pd(x)))
if (srch(x+1)==srch(x)<<1) return x+1;
return -1;
}
int main(){
n=_read(),q=_read();
for (int i=1;i<=n;i++) a[i]=_read(),mdfy(i,a[i]);
for (int p,x;q;q--)
p=_read(),x=_read(),mdfy(p,x-a[p]),a[p]=x,printf("%d\n",calc());
return 0;
}