HDU 3308 LCIS(区间合并 + 单点更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308

题意:给定n个数。2种操作。

  1. 更新第a个数为b。
  2. 查询区间[a,b]的最长连续上升子序列。

思路:裸的区间合并。每个结点存

  1. 从区间左端点开始的最长连续上升子序列的长度lm。
  2. 以区间右端点结束的最长连续上升子序列的长度rm。
  3. 区间的最长连续上升子序列的长度mx。
  4. 区间左端点的数值la。
  5. 区间右端点的数值ra。

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>

using namespace std;

#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

const int N = 5e5 + 10;
const int INF = 0x7f7f7f7f;

struct Node {
    int lm;
    int rm;
    int mx;
    int la;
    int ra;

    Node() {}

    Node(int a, int b, int c, int d, int e) {
        lm = a;
        rm = b;
        mx = c;
        la = d;
        ra = e;
    }
};

Node node[N << 2];

void pushup(int rt, int l, int r) {
    int m = (l + r) >> 1;
    node[rt].mx = max(node[rt << 1].mx, node[rt << 1 | 1].mx);
    if (node[rt << 1].ra < node[rt << 1 | 1].la)
        node[rt].mx = max(node[rt].mx, node[rt << 1].rm + node[rt << 1 | 1].lm);
    if (node[rt << 1].lm == m - l + 1 && node[rt << 1].ra < node[rt << 1 | 1].la)
        node[rt].lm = node[rt << 1].lm + node[rt << 1 | 1].lm;
    else
        node[rt].lm = node[rt << 1].lm;
    if (node[rt << 1 | 1].rm == r - m && node[rt << 1].ra < node[rt << 1 | 1].la)
        node[rt].rm = node[rt << 1 | 1].rm + node[rt << 1].rm;
    else
        node[rt].rm = node[rt << 1 | 1].rm;
    node[rt].la = node[rt << 1].la;
    node[rt].ra = node[rt << 1 | 1].ra;
}

void build(int l, int r, int rt) {
    if (l == r) {
        int x;
        scanf("%d", &x);
        node[rt].la = node[rt].ra = x;
        node[rt].lm = node[rt].rm = node[rt].mx = 1;
        return ;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    pushup(rt, l, r);
}

void update(int x, int v, int l, int r, int rt) {
    if (l == r) {
        node[rt].la = node[rt].ra = v;
        return ;
    }
    int m = (l + r) >> 1;
    if (x <= m)
        update(x, v, lson);
    else
        update(x, v, rson);
    pushup(rt, l, r);
}

Node query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
        return node[rt];
    }
    int m = (l + r) >> 1;
    Node ql = Node(0, 0, 0, 0, 0), qr = Node(0, 0, 0, 0, 0), res;
    if (L <= m)
        ql = query(L, R, lson);
    if (R > m)
        qr = query(L, R, rson);
    res.mx = max(ql.mx, qr.mx);
    if (ql.ra < qr.la)
        res.mx = max(res.mx, ql.rm + qr.lm);
    if (ql.lm == m - l + 1 && ql.ra < qr.la)
        res.lm = ql.lm + qr.lm;
    else
        res.lm = ql.lm;
    if (qr.rm == r - m && ql.ra < qr.la)
        res.rm = qr.rm + ql.rm;
    else
        res.rm = qr.rm;
    res.la = ql.la;
    res.ra = qr.ra;
    return res;
}

int main() {
    int t_case;
    scanf("%d", &t_case);
    for (int i_case = 1; i_case <= t_case; i_case++) {
        int n, m;
        scanf("%d%d", &n, &m);
        build(1, n, 1);

        for (int i_q = 1; i_q <= m; i_q++) {
            char op[3];
            int a, b;
            scanf("%s%d%d", op, &a, &b);
            if (op[0] == ‘Q‘) {
                a++;
                b++;
                Node res = query(a, b, 1, n, 1);
                printf("%d\n", res.mx);
            }
            else {
                a++;
                update(a, b, 1, n, 1);
            }
        }
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-28 16:14:41

HDU 3308 LCIS(区间合并 + 单点更新)的相关文章

HDU 3308 LCIS (线段树&#183;单点更新&#183;区间合并)

题意  给你一个数组  有更新值和查询两种操作  对于每次查询  输出对应区间的最长连续递增子序列的长度 基础的线段树区间合并  线段树维护三个值  对应区间的LCIS长度(lcis)  对应区间以左端点为起点的LCIS长度(lle)  对应区间以右端点为终点的LCIS长度(lri)  然后用val存储数组对应位置的值  当val[mid + 1] > val[mid] 的时候就要进行区间合并操作了 #include <cstdio> #include <algorithm>

hdu 3308 线段树 区间合并+单点更新+区间查询

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6592    Accepted Submission(s): 2866 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

hdu 3308 线段树,单点更新 求最长连续上升序列长度

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9713    Accepted Submission(s): 4215 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

HDU 3308 LCIS (端点更新+区间合并)

刚刚做了两道LCIS,碰到这道线段树,脑抽了似的写 线段树+dp(LCIS),贡献一发TLE. 才想到要区间合并,query函数写了好久.下面有详细注释,参见代码吧~~欢迎点赞,欢迎卖萌~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 #include<cstdio> #inc

hdu 3308 LCIS(线段树)

pid=3308" target="_blank" style="">题目链接:hdu 3308 LCIS 题目大意:给定一个序列,两种操作: Q l r:查询区间l,r中的最长连续递增序列长度 U p x:将位置p上的数改成x 解题思路:线段树上的区间合并,这是在左右子树合并的时候要推断一下是否满足递增就可以. #include <cstdio> #include <cstring> #include <algorit

HDU 3308 LCIS(线段树)

Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index counting from 0)Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b]. Input T in the first line, indicating

HDU 1166(线段树单点更新)

HDU 1166 题意:1-n个堡垒,人数在不断变化,多次查询 l-r人数和: 思路:线段树的单点更新: #include<iostream> #include<cstring> #include<cstdio> #include<string> #include<algorithm> #include<cmath> #include<map> #include<vector> #include<queu

HDU 3308 LCIS (线段树区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1

hdu 3308 LCIS(线段树区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5792    Accepted Submission(s): 2513 Problem Description Given n integers. You have two