一开始想用线段树维护, 然后发现太多细节了,QAQ.
我们 可以发现一个数可以被取到最大值, 那么直接把他删到0不会影响结果.
因为 两边的位置都不能能取到最大值并影响当前位置.
所以我们只需要知道有多少个位置取到最大值即可.
O ( m n log n ) O(mn\log n) O(mnlogn) 的做法是 直接排序, 然后把两边覆盖…
对于一段单调序列, 显然取第一大, 第三大, …
所以我们可以用树状数组维护奇偶的前缀和.
然后修改一个位置最多对旁边两条链有影响, 我们只需要暴力把影响减去, 后面加回来即可.
对于链的存储, 我们用 s e t set set 存极值点即可.
感谢扶咕咕的博客!!!
int n, a[N];
ll ans;
struct BIT {
ll c[N];
void add(int x, int v) { for( ; x <= n; x += x & -x) c[x] += v; }
ll ask(int x) { ll y = 0; while(x) y += c[x], x &= x - 1; return y;}
ll ask(int l, int r) { return ask(r) - ask(l - 1);}
} c[2];
set<int> s;
#define ev(x) (!((x) & 1))
void check(int x) {
if((a[x] > a[x - 1]) == (a[x] >= a[x + 1])) s.insert(x);
else s.erase(x);
}
void calc(IT l, IT r, int v) {//重算l~r之间的答案
while(l != r) {
auto t = r; t--;
if(a[*t] < a[*r]) ans += v * c[*r & 1].ask(*t + 1, *r);
else {
ans += v * c[*t & 1].ask(*t + 1, *r - 1);
auto p = r; p++;
if(p == s.end()) p--;
if(ev(*r - *t) && ev(*r - *p)) ans += v * a[*r];
}
r = t;
}
int x = *l;
if(a[x] >= a[x + 1]) return ;
if(s.begin() != l) l--;
++r; if(ev(x - *l) && ev(x - *r)) ans += v * a[x];
}
void upd(int x) {
int y; qr(y);
IT v = s.lower_bound(x), l = v, r = v; l--; r++;
if(l != s.begin()) l--;
if(r != s.end()) r++;
if(r == s.end()) r--;
calc(l, r, -1);
c[x & 1].add(x, y - a[x]); a[x] = y;
check(x); if(x > 1) check(x - 1); if(x < n) check(x + 1);
calc(l, r, 1);
}
void solve() {
qr(n); s.insert(0); s.insert(n + 1);
FOR(i, n) upd(i);
int x, m; qr(m); while(m--) qr(x), upd(x), pr2(ans);
}