【思路要点】
- 记 aia_iai 为卡牌的当前价值, Mini=Min{ai,ai+1,…,aN}Min_i=Min\{a_i,a_{i+1},\dots,a_N\}Mini=Min{ai,ai+1,…,aN} 。
- 引理: Ans=Min1+∑i≡1 (mod 2)Max{ai,Mini+1}Ans=Min_1+\sum_{i\equiv1\ (mod\ 2)}Max\{a_i,Min_{i+1}\}Ans=Min1+∑i≡1 (mod 2)Max{ai,Mini+1} 。
证明:
首先,先手玩家一定可以通过反转后手玩家的操作使得原本属于自己的权值到手。
并且,若先手玩家选择不反转后手玩家当前的操作,则意味着先手玩家放弃当前后手玩家所操作的数 iii ,但由于先手玩家最终一定会具有 N2+1\frac{N}{2}+12N+1 个数,因此先手玩家在后续的过程中一定将会多出一个数,其最差情况为 Mini+1Min_{i+1}Mini+1 ,并且后手玩家可以通过操作非 Mini+1Min_{i+1}Mini+1 的位置使得最差情况取到。- 因此,考虑 aia_iai 从后向前的单调队列,由在队列中的点分成的各段 [l,r)[l,r)[l,r) 对答案的贡献即为 aia_iai 在 (l,r)(l,r)(l,r) 内奇数位和以及端点 lll 处的贡献。
- 注意到操作仅包含减法,用树状数组维护 aia_iai 的奇数位,并用平衡树维护单调队列即可,每次操作单调队列至多加入一个元素,因此单调队列的总变化是 O(N+M)O(N+M)O(N+M) 的。
- 时间复杂度 O(MLogN+NLogN)O(MLogN+NLogN)O(MLogN+NLogN) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct BinaryIndexTree { int n; ll a[MAXN]; void init(int x) { n = x; memset(a, 0, sizeof(a)); } void modify(int x, int d) { for (int i = x; i <= n; i += i & -i) a[i] += d; } ll query(int x) { ll ans = 0; for (int i = x; i >= 1; i -= i & -i) ans += a[i]; return ans; } ll query(int l, int r) { if (l > r) return 0; ll ans = 0; for (int i = r; i >= 1; i -= i & -i) ans += a[i]; for (int i = l - 1; i >= 1; i -= i & -i) ans -= a[i]; return ans; } } BIT; int n, m, a[MAXN]; set <int> st; ll ans; ll calc(int l, int r) { ll ans = BIT.query(l + 1, r - 1); if ((l & 1) && l < r) ans += a[r]; return ans; } ll getans() { int pos = *st.begin(); ll res = ans + BIT.query(1, pos - 1); return res + a[pos]; } int main() { read(n), BIT.init(n); for (int i = 1; i <= n; i++) { read(a[i]); if (i & 1) BIT.modify(i, a[i]); } int Min = 2e9; for (int i = n; i >= 1; i--) if (a[i] < Min) { Min = a[i]; if (i != n) ans += calc(i, *st.begin()); st.insert(i); } writeln(getans()), read(m); for (int i = 1; i <= m; i++) { int x, y; read(x), read(y); auto pos = st.lower_bound(x); int last = *pos; if (*pos == x && x != n) { auto suf = pos; suf++; ans -= calc(*pos, *suf); } while (pos != st.begin()) { auto pre = pos; pre--; ans -= calc(*pre, last); if (a[x] - y <= a[*pre]) { last = *pre; st.erase(pre); } else break; } a[x] -= y; if (x & 1) BIT.modify(x, -y); if (*pos == x) { if (x != n) { auto suf = pos; suf++; ans += calc(*pos, *suf); } if (pos != st.begin()) { auto pre = pos; pre--; ans += calc(*pre, *pos); } } else { if (a[x] < a[*pos]) { st.insert(x); ans += calc(x, *pos); pos = st.lower_bound(x); if (pos != st.begin()) { auto pre = pos; pre--; ans += calc(*pre, *pos); } } else if (pos != st.begin()) { auto pre = pos; pre--; ans += calc(*pre, *pos); } } writeln(getans()); } return 0; }