[二分][树状数组] Jzoj P5871 挑战
题解
- 首先,先将所有数加入树状数组里,求出在没修改前的ans
- 然后,修改后,将相应位置的树状数组里加上y-p[x]
- 如果,修改的位置大于ans的位置,则输出ans
- 否则,判断1~x-1是否等于x
- 若不等于,则二分出一个mid,为最小大于当前x两倍的位置
- while一直找,知道找到相等的
代码
1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 int n,m,sum,ans,p[200010],sz[200010]; 5 void insert(int x,int y) { for (;x<=n;x+=x&-x) sz[x]+=y; } 6 int query(int x) 7 { 8 int r=0; 9 for (;x;x-=x&-x) r+=sz[x]; 10 return r; 11 } 12 int ef(int x) 13 { 14 int mx=query(x),l=x+1,r=n,mid,ans=0; 15 while (l<=r) 16 { 17 mid=(l+r)>>1; 18 if (query(mid)>=mx*2) r=mid-1,ans=mid; else l=mid+1; 19 } 20 return ans; 21 } 22 int main() 23 { 24 freopen("challenge.in","r",stdin); 25 freopen("challenge.out","w",stdout); 26 scanf("%d%d",&n,&m),ans=n+1; 27 for (int i=1;i<=n;i++) 28 { 29 scanf("%d",&p[i]); 30 insert(i,p[i]); 31 if (p[i]==sum) ans=min(ans,i); 32 sum+=p[i]; 33 } 34 for (int i=1;i<=m;i++) 35 { 36 int x,y; 37 scanf("%d%d",&x,&y); 38 insert(x,y-p[x]),p[x]=y; 39 if (x>ans) printf("%d\n",ans); 40 else 41 { 42 ans=n+1; 43 if (query(x)==query(x-1)*2) ans=x; 44 else 45 { 46 while(x<=n) 47 { 48 int y=ef(x); 49 if (y==0) break; 50 if (query(y)==query(y-1)*2) 51 { 52 ans=y; 53 break; 54 } 55 x=y; 56 } 57 } 58 if (ans==n+1) printf("-1\n"); else printf("%d\n",ans); 59 } 60 } 61 return 0; 62 }