Codeforces 992 E. Nastya and King-Shamans
\(>Codeforces\space992 E. Nastya and King-Shamans<\)
題目大意 : 給你一個長度為 \(n\) 的序列,有 \(q\) 次操作,每一次操作將一個數 \(A_i\) 改為另外一個數。每一次操作結束時,你需要找出一個位置 \(x\) 滿足 \(A_x = sum_{x-1}\) 其中 \(sum\) 表示前綴和
$n , q \leq 2 \times 10^5 0 \leq A_i \leq 10^9 $
解題思路 :
博主親測分塊加均攤分析的做法會因為常數太大 \(TLE\) 掉,在此就不多討論了
問題要求出滿足 \(A_x = sum_{x-1}\)
我們考慮從 \(A_{p=1}\) 開始跳,每一次跳到其後面一個最小的 \(k - 1\) ,滿足\(sum_k \geq 2 \times sum_p\)
可以證明如果有答案且 \(sum_{ans} > 0\),那麽答案一定在所有的 \(k\) 之中產生
不妨用反證法來證明,假設當且跳到點 \(k\) ,接下來選取的點是 \(k‘ \ (k < k‘)\) ,對於 \(k < i < k‘ - 1\)
如果說 \(i\) 是答案的話,設 \(y\) 為 第一個滿足 $ sum_y \geq 2 \times sum_i$ 的點。
因為\(sum_y \geq sumk\) 所以必然有 $ y \geq k‘ $ ,如果 \(i < k‘ - 1\) 那麽 $ y - i > 1$ , \(i\) 不是答案
所以證明了這樣跳,如果有答案的話答案必然在跳到的點上
所以可以用樹狀數組維護前綴和,每一次暴力二分跳,跳 \(log\) 次就能跳完,總復雜度是\(O(nlogn^3)\)
/*program by mangoyang*/ #include<bits/stdc++.h> #define inf (0x7f7f7f7f) #define Max(a, b) ((a) > (b) ? (a) : (b)) #define Min(a, b) ((a) < (b) ? (a) : (b)) typedef long long ll; using namespace std; template <class T> inline void read(T &x){ int f = 0, ch = 0; x = 0; for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = 1; for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - ‘0‘; if(f) x = -x; } #define N (300005) #define int ll ll c[N], a[N], n, q; inline void add(int x, ll y){ for(int i = x; i <= n; i += i & -i) c[i] += y; } inline ll sum(int x){ ll ans = 0; for(int i = x; i; i -= i & -i) ans += c[i]; return ans; } inline void solve(){ int x = 1; if(sum(1) == 0) return (void)( puts("1") ); while(x < n){ int l = x + 1, r = n, k = x, now = 2 * sum(x); if(sum(x + 1) == now) return (void) (printf("%d\n", x + 1)); while(l <= r){ int mid = l + r >> 1; if(sum(mid) < now) k = mid, l = mid + 1; else r = mid - 1; } if(k + 1 > n) break; x = (k == x) ? k + 1 : k; } puts("-1"); } main(){ read(n), read(q); for(int i = 1; i <= n; i++) read(a[i]), add(i, a[i]); for(int i = 1; i <= q; i++){ int x, y; read(x), read(y); add(x, y - a[x]), a[x] = y, solve(); } return 0; }
Codeforces 992 E. Nastya and King-Shamans