CodeForces 992E (势能线段树)
https://codeforces.com/problemset/problem/992/E
题意: 单点修改,询问整个数列中满足 \(a_{i} = s_{i-1}\) 的任意一个i (si是i的前缀和)
思路:
- 要满足\(a_{i} = s_{i-1}\),必有\(s_{i} = s_{i-1} * 2\),所有最多有log sn个位置满足
- 线段树维护\(a_{i} - s_{i-1}\), 线段树上询问最大值大于0的区间,找到值等于0的位置
- 时间复杂度 \(nlogn^2\)
#include<bits/stdc++.h>
//#include <bits/extc++.h>
using namespace std;
// using namespace __gnu_cxx;
// using namespace __gnu_pbds;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define ull unsigned long long
#define li __int128_t
#define PII pair<int, int>
#define re register
//#define int long long
const int N = 2e5 + 5;
const int M = 1e6 + 5;
const int mod = 998244353;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
ll a[N], s[N]; int n; int ans = -1;
struct Tree {
ll mx, lazy;
}tree[N << 2];
inline void pushup( int rt ) {
tree[rt].mx = max( tree[rt << 1].mx, tree[rt << 1 | 1].mx );
}
inline void pushdown( int l, int r, int rt ) {
if( !tree[rt].lazy ) return;
tree[ rt << 1 ].lazy += tree[rt].lazy;
tree[ rt << 1 | 1 ].lazy += tree[rt].lazy;
tree[ rt << 1 ].mx += tree[rt].lazy;
tree[ rt << 1 | 1 ].mx += tree[rt].lazy;
tree[rt].lazy = 0;
}
inline void build( int l, int r, int rt ) {
if( l == r ) {
tree[rt].mx = a[l] - s[l - 1];
return;
}
int mid = l + r >> 1;
build( l, mid, rt << 1 ); build( mid + 1, r, rt << 1 | 1 );
pushup(rt);
}
inline void modify( int a, int b, ll c, int l, int r, int rt ) {
if( l > b || r < a ) return ;
if( l >= a && r <= b ) {
tree[rt].mx += c; tree[rt].lazy += c;
return;
}
pushdown( l, r, rt );
int mid = l + r >> 1;
modify( a, b, c, l, mid, rt << 1 );
modify( a, b, c, mid + 1, r, rt << 1 | 1 );
pushup(rt);
}
inline void query( int l, int r , int rt) {
if( ans != -1 ) return;
if( l == r ) {
if( !tree[rt].mx ) ans = l;
return;
}
pushdown( l, r, rt );
int mid = l + r >> 1;
if( tree[rt << 1].mx >= 0 ) query( l, mid, rt << 1 );
if( tree[rt << 1 | 1].mx >= 0 ) query( mid + 1, r, rt << 1 | 1 );
}
int main() {
int q; n = read(), q = read();
for ( re int i = 1; i <= n; ++ i ) a[i] = read(), s[i] = s[i - 1] + a[i];
build( 1, n, 1 );
while ( q --) {
ll pos, val; pos = read(), val = read();
val -= a[pos];
modify( pos, pos, val, 1, n, 1 );
if ( pos < n ) modify( pos + 1, n, -val, 1, n, 1 );
a[pos] += val;
query( 1, n, 1 );
printf("%d\n", ans);
ans = -1;
}
return 0;
}