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 &lt; k ′ ) k′ (k&lt;k′) k(k<k),对于 k &lt; i &lt; k ′ − 1 k&lt;i&lt;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 &lt; k ′ − 1 i&lt;k′−1 i<k1 那么 y − i &gt; 1 y−i&gt;1 yi>1 ,i 不是答案

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

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

------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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值