HDU3308LCIS(線段樹)

題目鏈接hdu3308

在這裏插入圖片描述
在這裏插入圖片描述

題目大意:大致就是給一個帶修改動態的序列,讓你求每次詢問的區間最長上升子序列的長度,這個上升子序列是連續的。

思路:由於是連續的,並且是區間問題可以考慮用線段樹去維護它。如何維護這個線段樹呢?
我們發現一個區間的LCIS得到的貢獻只有三種情況:左區間、右區間、左右區間。如果維護左右區間的LCIS的長度的話到時只要取一個最大的上來即可。如何維護上升和左右區間呢?*
可以多一個區間的前綴最大LCIS和後綴的最大LCIS,在修改的時候父節點可以通過斷掉的端點去修改當前的LCIS,因爲比如端點如果連續,當前的LCIS會等於左區間後綴+右區間前綴,其他情況同理,詳見代碼


Code

#include <stdio.h>
#include <string.h>
#define MAXN 100005

struct Node {
    int l, r;
    int suf, pre, lcis;
};
Node LTree[MAXN<<2];
int n, m, val[MAXN];

inline int max(int a, int b) {
    return a > b ? a : b;
}

void PushUp(int idx) {
    int mid = LTree[idx << 1].r;
    if (val[mid] < val[mid+1]) {
        LTree[idx].pre = LTree[idx << 1].pre;
        if (LTree[idx << 1].pre == LTree[idx << 1].r - LTree[idx << 1].l + 1)
            LTree[idx].pre += LTree[idx << 1 | 1].pre;
        LTree[idx].suf = LTree[idx << 1 | 1].suf;
        if (LTree[idx << 1 | 1].suf == LTree[idx << 1 | 1].r - LTree[idx << 1 | 1].l + 1)
            LTree[idx].suf += LTree[idx << 1].suf;
        LTree[idx].lcis = max(max(LTree[idx << 1].lcis, LTree[idx << 1 | 1].lcis), LTree[idx << 1].suf + LTree[idx << 1 | 1].pre);
    } else {
        LTree[idx].pre = LTree[idx << 1].pre;
        LTree[idx].suf = LTree[idx << 1 | 1].suf;
        LTree[idx].lcis = max(LTree[idx << 1].lcis, LTree[idx << 1 | 1].lcis);
    }
}

void build(int l, int r, int idx) {
    LTree[idx].l = l;
    LTree[idx].r = r;
    if (l == r) {
        LTree[idx].suf = LTree[idx].pre = LTree[idx].lcis = 1;
        return ;
    }
    int mid = l + (r - l >> 1);
    build(l, mid, idx << 1);
    build(mid+1, r, idx << 1 | 1);
    PushUp(idx);
}

void update(int k, int num, int idx) {
    if (LTree[idx].l == k && LTree[idx].r == k) {
        val[k] = num;
        return ;
    }
    int mid = LTree[idx].l + (LTree[idx].r - LTree[idx].l >> 1);
    if (k > mid) update(k, num, idx << 1 | 1);
    else update(k, num, idx << 1);
    PushUp(idx);
}

int query_pre(int l, int r, int idx) {
    if (l <= LTree[idx].l && r >= LTree[idx].r) {
        return LTree[idx].pre;
    }
    int mid = LTree[idx].l + (LTree[idx].r - LTree[idx].l >> 1);
    if (r <= mid)
        return query_pre(l, r, idx << 1);
    else if (l > mid)
        return query_pre(l, r, idx << 1 | 1);
    else {
        int pre = query_pre(l, mid, idx << 1);
        if (val[mid] < val[mid+1] && pre == mid - l + 1) pre += query_pre(mid+1, r, idx << 1 | 1);
        return pre;
    }
}

int query_suf(int l, int r, int idx) {
    if (l <= LTree[idx].l && r >= LTree[idx].r) {
        return LTree[idx].suf;
    }
    int mid = LTree[idx].l + (LTree[idx].r - LTree[idx].l >> 1);
    if (r <= mid)
        return query_suf(l, r, idx << 1);
    else if (l > mid)
        return query_suf(l, r, idx << 1 | 1);
    else {
        int suf = query_suf(mid+1, r, idx << 1 | 1);
        if (val[mid] < val[mid+1] && suf == r - mid) suf += query_suf(l, mid, idx << 1);
        return suf;
    }
}

int query(int l, int r, int idx) {
    if (l <= LTree[idx].l && r >= LTree[idx].r) {
        return LTree[idx].lcis;
    }
    int mid = LTree[idx].l + (LTree[idx].r - LTree[idx].l >> 1);
    if (r <= mid)
        return query(l, r, idx << 1);
    else if (l > mid)
        return query(l, r, idx << 1 | 1);
    else {
        int rv = query(l, mid, idx << 1);
        int lv = query(mid+1, r, idx << 1 | 1);
        int mv = 0;
        if (val[mid] < val[mid+1]) {
//            mv = LTree[idx << 1].suf + LTree[idx << 1 | 1].pre; 易錯,查詢的[l, r]區間不一定就是左右子樹的全部
            mv = query_suf(l, mid, idx << 1) + query_pre(mid+1, r, idx << 1 | 1);
        }
        return max(max(rv, lv), mv);
    }
}


int main() {
    char cmd[20];
    int u, v, i, T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        memset(val, 0, sizeof(val));
        for (i = 1; i <= n; i++) scanf("%d", &val[i]);
        build(1, n, 1);
        for (i = 1; i <= m; i++) {
            getchar();
            scanf("%s %d %d", &cmd, &u, &v);
            if (cmd[0] == 'Q') {
                printf("%d\n", query(u+1, v+1, 1));
            } else if (cmd[0] == 'U') {
                update(u+1, v, 1);
            }
        }
    }
    return 0;
}

查詢右左子樹的前後綴改成這個效率可變成O(1),即查詢的效率變成O(logn):mv = min(LTree[idx << 1].suf, mid - l + 1) + min(LTree[idx << 1 | 1].pre, r - mid);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章