cf739 C. Alyona and towers(線段樹)
阿新 • • 發佈:2021-12-30
題意:
給定陣列,要求實現兩種操作:區間加、查詢陣列中最長的 “先嚴格上升再嚴格下降” 的連續子區間的長度。
注意只嚴格上升或只嚴格下降或只有一個元素也是合法的。
思路:
把長為n的原陣列處理成相鄰項的差,長為n-1。
考慮相鄰項的差的符號,1,0,-1表示大於零,等於零,小於零。滿足條件的形式為 \(+1,+1,+1,-1,-1\) ,即差的符號函式值非嚴格遞減,不能出現0。
用線段樹維護差的符號函式值,記錄區間最大的連續非嚴格遞減子列的長度、從左端點開始的長度和從右端點開始的長度。合併區間時要判斷左右兒子相接的地方能不能合併。
因為差分了所以只需單點修改。查詢時直接輸出根節點上的答案。另外再實現個建樹函式和pushup即可,不需要pushdown。pushup和main函式中有挺多細節,其他幾個函式跟普通線段樹差不多。
對於每次修改,首先直接修改差分陣列(即原陣列),如果改變了差的符號才需要改線段樹。
n=1時根本沒有相鄰項,特判一下。
#include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 3e5 + 5; ll w[N]; int sgn(ll x) { //返回x的符號 if(x > 0) return 1; if(x < 0) return -1; return 0; } struct node { int l, r, len, llen, rlen; } tr[N*4]; void pushup(int u) { tr[u].len = max(tr[u<<1].len, tr[u<<1|1].len); tr[u].llen = tr[u<<1].llen, tr[u].rlen = tr[u<<1|1].rlen; if(w[tr[u<<1].r] && w[tr[u<<1|1].l] && sgn(w[tr[u<<1].r]) >= sgn(w[tr[u<<1|1].l])) { tr[u].len = max(tr[u].len, tr[u<<1].rlen + tr[u<<1|1].llen); if(tr[u<<1].llen == tr[u<<1].r - tr[u<<1].l + 1) tr[u].llen += tr[u<<1|1].llen; if(tr[u<<1|1].rlen == tr[u<<1|1].r - tr[u<<1|1].l + 1) tr[u].rlen += tr[u<<1].rlen; } } void build(int u, int l, int r) { if(l == r) //只維護符號 { bool tmp = w[l]; tr[u] = {l, r, tmp, tmp, tmp}; } else { tr[u] = {l, r}; int mid = l + r >> 1; build(u<<1, l, mid), build(u<<1|1, mid+1, r); pushup(u); } } void modify(int u, int p, int x) //把單點p改為x { if(tr[u].l == tr[u].r) { bool tmp = x; tr[u] = {tr[u].l, tr[u].r, tmp, tmp, tmp}; return; } int mid = tr[u].l + tr[u].r >> 1; if(p <= mid) modify(u<<1, p, x); else modify(u<<1|1, p, x); pushup(u); } signed main() { int n, q; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%lld", &w[i]); if(n == 1) { scanf("%d", &q); while(q--) puts("1"); return 0; } for(int i = 1; i < n; i++) w[i] = w[i+1] - w[i]; //差分 build(1, 1, n-1); //維護n-1個相鄰差 scanf("%d", &q); while(q--) { int l, r, d; scanf("%d%d%d", &l, &r, &d); if(l > 1) { if(sgn(w[l-1]) != sgn(w[l-1]+d)) w[l-1] += d, modify(1, l-1, sgn(w[l-1])); else w[l-1] += d; } if(r < n) { if(sgn(w[r]) != sgn(w[r]-d)) w[r] -= d, modify(1, r, sgn(w[r])); else w[r] -= d; } printf("%d\n", tr[1].len + 1); } return 0; }