当前位置: 代码迷 >> 综合 >> 线段树区间合并 hdu3308 LCIS
  详细解决方案

线段树区间合并 hdu3308 LCIS

热度:14   发布时间:2023-12-14 04:13:34.0

要求的是最长连续上升子序列,如果看到连续两个字就好做了


然后就是一个单点更新的裸区间合并,在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<<1int 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;
}