要求的是最长连续上升子序列,如果看到连续两个字就好做了
然后就是一个单点更新的裸区间合并,在push_up很好写,但是query的时候要注意一些
1.m可能并不在L,R中间,也就是说lson和rson只用了一个,并没有都使用,那么就没必要考虑A[m]<A[m+1]时把区间的中间部分连续长度算出来
2.在合并左右答案的时候,因为LA,RA都是针对下一个节点的区间的,而并不是针对L和R
所以,合并的时候,中间部分只有min(RA[rt << 1], m - L + 1) + min(LA[rt << 1 | 1], R - m)
#include<cstdio> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<functional> #include<algorithm> using namespace std; typedef long long LL; const int MX = 100000 + 5; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define root 0,n-1,1 #define NR rt<<1|1 #define NL rt<<1 int A[MX]; int LA[MX << 2], MA[MX << 2], RA[MX << 2]; void push_up(int rt, int m, int len) { LA[rt] = LA[NL]; RA[rt] = RA[NR]; MA[rt] = max(MA[NL], MA[NR]); if(A[m] < A[m + 1]) { if(LA[rt] == len - (len >> 1)) { LA[rt] += LA[NR]; MA[rt] = max(MA[rt], LA[rt]); } if(RA[rt] == len >> 1) { RA[rt] += RA[NL]; MA[rt] = max(MA[rt], RA[rt]); } MA[rt] = max(MA[rt], RA[NL] + LA[NR]); } } void build(int l, int r, int rt) { if(l == r) { LA[rt] = MA[rt] = RA[rt] = 1; scanf("%d", &A[l]); return; } int m = (l + r) >> 1; build(lson); build(rson); push_up(rt, m, r - l + 1); } int query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) { return MA[rt]; } int m = (l + r) >> 1, ansm = 0, ansl = 0, ansr = 0; if(L <= m) ansl = query(L, R, lson); if(R > m) ansr = query(L, R, rson); if(L <= m && m < R && A[m] < A[m + 1]) { ansm = min(RA[NL], m - L + 1) + min(LA[NR], R - m); } return max(ansm, max(ansl, ansr)); } void update(int x, int d, int l, int r, int rt) { if(l == r) { A[l] = d; return; } int m = (l + r) >> 1; if(x <= m) update(x, d, lson); else update(x, d, rson); push_up(rt, m, r - l + 1); } int main() { int T, n, m; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); build(root); for(int i = 1; i <= m; i++) { char op[10]; int a, b; scanf("%s%d%d", op, &a, &b); if(op[0] == 'Q') printf("%d\n", query(a, b, root)); else update(a, b, root); } } return 0; }