【題解】HDU 3308. LCIS

【題目敘述】https://vjudge.net/problem/HDU-3308
【解題想法】線段樹 (Segment Tree),LIS (最長遞增子序列)

  • 思考:左右兩個區間的LIS長度該怎麼pushup?

  • arr[maxn]:存放讀入的數值
  • struct node:定義線段樹每個節點存放的資料,開4倍空間
    • l, r:每個節點覆蓋區間的左界和右界
    • L:區間從最左端(包含)的最長遞增子序列長度
    • R:區間從最右端(包含)的最長遞增子序列長度
    • mx:[l, r] 區間內的最長遞增子序列長度
  • pull( ):依node的資料結構定義進行
  • query( ):
    • 當一個節點覆蓋的區間 [l, r] 完全落於 [ql, qr] 區間內,回傳該節點
    • 依照 [ql, qr] 要求,搜尋左兒子 and/or 右兒子
    • 回傳的節點,需再進行pull( ),計算出真正的LIS長度
#include <iostream>
#include <cmath>
using namespace std;

struct node{
    //區間 [l, r]
    //L:區間從左往右的最長遞增子序列長度
    //R:區間從右往左的最長遞減子序列長度
    //mx:區間內的最長遞增子序列長度
    int l, r, L, R, mx;
};

int n, m, Case, a, b, arr[100005];
char c;
node lis[100005 << 2];

void pull(node &x, node l, node r){
    x.l = l.l;
    x.r = r.r;
    x.L = l.L;
    x.R = r.R;
    x.mx = max(l.mx, r.mx);
    if (arr[l.r] < arr[r.l]){
        x.mx = max(x.mx, l.R + r.L);
        if (l.R == l.r-l.l+1) x.L = max(x.L, x.mx);
        if (r.L == r.r-r.l+1) x.R = max(x.R, x.mx);
    }
}

void build(int x, int l, int r){
    if (l == r){
        lis[x].l = l;
        lis[x].r = r;
        lis[x].L = 1;
        lis[x].R = 1;
        lis[x].mx = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(x<<1, l, mid);
    build(x<<1|1, mid+1, r);
    pull(lis[x], lis[x<<1], lis[x<<1|1]);
}

node query(int x, int l, int r, int ql, int qr){
    if(ql <= l && r <= qr){
        return lis[x];
    }
    int mid = (l + r) >> 1;
    if(qr <= mid){
        return query(x<<1, l, mid, ql, qr);
    }else if(mid < ql){
        return query(x<<1|1, mid+1, r, ql, qr);
    }else{
        node left = query(x<<1, l, mid, ql, qr);
        node right = query(x<<1|1, mid+1, r, ql, qr);
        node ans;
        pull(ans, left, right);
        return ans;
    }
}

void update(int x, int l, int r){
    if (l == r){
        arr[a] = b;
        return;
    }
    int mid = (l + r) >> 1;
    if (a <= mid) update(x<<1, l, mid);
    else update(x<<1|1, mid+1, r);
    pull(lis[x], lis[x<<1], lis[x<<1|1]);
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin >> Case;
    while (Case--){
        cin >> n >> m;
        for (int i = 1; i <= n; i++){
            cin >> arr[i];
        }
        build(1, 1, n);
        for (int i = 0; i < m; i++){
            cin >> c >> a >> b;
            a++;
            if (c == 'Q'){
                b++;
                cout << query(1, 1, n, a, b).mx << "\n";
            }else{
                update(1, 1, n);
            }
        }
    }
}
分享本文 Share with friends