线段树区间合并 hdu3308 LCIS

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


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


你可能感兴趣的:(线段树区间合并 hdu3308 LCIS)