传送门
容易想到同时维护\(a_{i} + i\)和\(a_{i} - i\),但是我一开始的做法是更新后再扫一遍才能更新出答案,这样不仅时间上爆炸,答案还更新不全。其实完全可以push_up的时候更新答案,这样不仅不会浪费复杂度,还不会漏情况
```cpp
#include<bits/stdc++.h>using namespace std;long long t;
const long long N = 2e5 + 10;
long long n,q,ans;
long long a[N];
struct node {long long pmax,pmin,nmax,nmin,ans1,ans2;
}tr[4 * N];node up(node x,node y) {node res;res.pmax = max(x.pmax,y.pmax);res.pmin = min(x.pmin,y.pmin);res.nmax = max(x.nmax,y.nmax);res.nmin = min(x.nmin,y.nmin);res.ans1 = max({x.ans1,y.ans1,x.pmax - y.pmin});res.ans2 = max({x.ans2,y.ans2,y.nmax - x.nmin});return res;
}void build(long long k,long long l,long long r) {if(l == r) {tr[k].pmax = tr[k].pmin = a[l] + l;tr[k].nmax = tr[k].nmin = a[l] - l;tr[k].ans1 = tr[k].ans2 = 0;return;}long long mid = (l + r) >> 1;build(k * 2,l,mid);build(k * 2 + 1,mid + 1,r);tr[k] = up(tr[k * 2],tr[k * 2 + 1]);
}void change(long long k,long long l,long long r,long long x,long long v) {if(l > x || r < x) return;if(l == r && l == x) {tr[k].pmax = tr[k].pmin = v + l;tr[k].nmax = tr[k].nmin = v - l;return;}long long mid = (l + r) >> 1;change(k * 2,l,mid,x,v);change(k * 2 + 1,mid + 1,r,x,v);tr[k] = up(tr[k * 2],tr[k * 2 + 1]);
}node query(long long k,long long l,long long r,long long x,long long y) {if(l > y || r < x) return (node){-1000000000,1000000000,-1000000000,1000000000,0,0};if(l >= x && r <= y) return tr[k];long long mid = (l + r) >> 1;node res;res = up(query(k * 2,l,mid,x,y),query(k * 2 + 1,mid + 1,r,x,y));return res;
}void solve() {cin >> n >> q;for(long long i = 1;i <= n;i++) cin >> a[i];build(1,1,n);node tmp = query(1,1,n,1,n);cout << max(tmp.ans1,tmp.ans2) << '\n';for(long long p,x,i = 1;i <= q;i++) {cin >> p >> x;change(1,1,n,p,x);node tmp = query(1,1,n,1,n);cout << max(tmp.ans1,tmp.ans2) << '\n';}
}signed main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> t;while(t--) solve();return 0;
}