CF992E Nastya and King-Shamans
题面翻译
给定一个序列 \(a_i\) ,记其前缀和序列为 \(s_i\) ,有 \(q\) 个询问,每次单点修改,询问是否存在一个 \(i\) 满足 \(a_i=s_{i-1}\) ,有多解输出任意一个,无解输出 \(-1\) 。
样例 #1
样例输入 #1
2 1
1 3
1 2
样例输出 #1
-1
样例 #2
样例输入 #2
3 4
2 2 3
1 1
1 2
2 4
3 6
样例输出 #2
3
2
-1
3
样例 #3
样例输入 #3
10 7
0 3 1 4 6 2 7 8 10 1
2 5
1 3
9 36
4 10
4 9
1 2
1 0
样例输出 #3
1
-1
9
-1
4
-1
1
分析
考虑当 \(a_i\geq s_{i-1}\) 时,则有 \(s_i\geq 2s_{i-1}\),那么如果长度为 \(n\),那么满足条件的个数不超过 \(\log s_n\) 次。
建线段树维护 \(a_i-s_{i-1}\) 的区间最大值(因为只需要在区间 \(max>0\) 时才递归)由于上面的性质,叶子结点不超过 \(\log s_n\),复杂度正确。
进行修改操作,首先单点 \(a[x]=y\),再考虑哪些 \(s\) 值受到影响:\([x+1,n]\),又因为区间维护的是 \(a_i-s_{i-1}\) 前面带个减号,所以进行区间加 \(-y\),注意 \(x=n\) 时要特判越界。
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
return x*f;
}
int maxx[200005<<2],tag[200005<<2],a[200005],s[200005],n,q,res;
void pushup(int num){maxx[num]=max(maxx[num<<1],maxx[num<<1|1]);}
void pushdown(int num){
if(!tag[num])return;
maxx[num<<1]+=tag[num],maxx[num<<1|1]+=tag[num];
tag[num<<1]+=tag[num],tag[num<<1|1]+=tag[num];
tag[num]=0;
}
void build(int l,int r,int num){
if(l==r){maxx[num]=a[l]-s[l-1];return;}
int mid=l+r>>1;
build(l,mid,num<<1),build(mid+1,r,num<<1|1);
pushup(num);
}
void add(int l,int r,int num,int x,int y,int k){
if(x>r||y<l)return;
if(x<=l&&r<=y){
maxx[num]+=k,tag[num]+=k;
return;
}
pushdown(num);
int mid=l+r>>1;
add(l,mid,num<<1,x,y,k),add(mid+1,r,num<<1|1,x,y,k);
pushup(num);
}
void query(int l,int r,int num){
if(res^-1)return;
if(l==r){if(maxx[num]==0)res=l;return;}
pushdown(num);
int mid=l+r>>1;
if(maxx[num<<1]>=0)query(l,mid,num<<1);
if(maxx[num<<1|1]>=0)query(mid+1,r,num<<1|1);
}
signed main(){
n=read(),q=read();
for(int i=1;i<=n;i++)a[i]=read(),s[i]=s[i-1]+a[i];
build(1,n,1);
for(int i=1,x,y,k;i<=q;i++){
x=read(),k=read();res=-1;
y=k-a[x],a[x]=k,add(1,n,1,x,x,y);
if(x^n)add(1,n,1,x+1,n,-y);
query(1,n,1);
printf("%lld\n",res);
}
return 0;
}

浙公网安备 33010602011771号