codeforces 992E. Nastya and King-Shamans

树状数组 二分

题目传送门

题目大意: 维护一个数列,每次操作为先修改一个数,再询问是否存在一个位置 i i i满足 w [ i ] = s u m [ i − 1 ] w[i]=sum[i-1] w[i]=sum[i1]并输出这个位置。

妙蛙

问题要求出满足 A x = s u m x − 1 A_x=sum_{x−1} Ax=sumx1 的位置,这个可以转化为 s u m x = 2 s u m x − 1 sum_x=2sum_{x−1} sumx=2sumx1

我们考虑从 A p = 1 A_p=1 Ap=1 开始跳,每一次跳到其后面一个最小的 k − 1 k−1 k1 ,满足 s u m k ≥ 2 s u m p sum_k≥2sum_p sumk2sump

可以证明如果有答案且 s u m a n s > 0 sum_{ans}>0 sumans>0,那么答案一定在所有的 k k k 之中产生

不妨用反证法来证明,假设当且跳到点 k k k ,接下来选取的点是 k ′ ( k < k ′ ) k′ (k<k′) k(k<k),对于 k < i < k ′ − 1 k<i<k′−1 k<i<k1

如果说 i i i 是答案的话,设 y y y 为 第一个满足 s u m y ≥ 2 s u m i sum_y\geq2sum_i sumy2sumi 的点。

因为 s u m y ≥ s u m k sum_y≥sum_k sumysumk 所以必然有 y ≥ k ′ y≥k′ yk ,如果 i < k ′ − 1 i<k′−1 i<k1 那么 y − i > 1 y−i>1 yi>1 ,i 不是答案

所以证明了这样跳,如果有答案的话答案必然在跳到的点上

所以可以用树状数组维护前缀和,每一次暴力二分跳,跳 l o g log log 次就能跳完,总复杂度是 O ( n l o g 3 n ) O(nlog^3n) O(nlog3n)

------Mangoyang

代码:

#include
#include
#include
#include
#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;
}

你可能感兴趣的:(其他网站,数据结构---树状数组,其他---二分/三分,蒟蒻zxl的Blog专栏)