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 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 the case number.
Each case starts with two integers n , m(0<n,m<=105).
The next line has n integers(0<=val<=105).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=105)
OR
Q A B(0<=A<=B< n).

Output

For each Q, output the answer.

Sample Input

1

10 10

7 7 3 3 5 9 9 8 1 8

Q 6 6

U 3 4

Q 0 1

Q 0 5

Q 4 7

Q 3 5

Q 0 2

Q 4 6

U 6 10

Q 0 9

Sample Output

1

1

4

2

3

1

2

5

题意:求区间连续递增的最大个数,Q是询问区间内最大的LCIS

U是更新节点

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 6;
int llen[maxn << 2], rlen[maxn << 2], len[maxn << 2], tree[maxn];
void pushup(int l, int r, int id)
{
    int m = (l + r) >> 1;
    llen[id] = llen[id << 1];
    rlen[id] = rlen[id << 1 | 1];
    if (tree[m + 1] > tree[m])
    {
        if (llen[id << 1] == m - l + 1)
            llen[id] += llen[id << 1 | 1];
        if (rlen[id << 1 | 1] == r - m)
            rlen[id] += rlen[id << 1];
        len[id] = max(max(len[id << 1], len[id << 1 | 1]), rlen[id << 1] + llen[id << 1 | 1]);
    }
    else
        len[id] = max(len[id << 1], len[id << 1 | 1]);
}
void build(int l, int r, int id)
{
    if (l == r)
    {
        scanf("%d", &tree[l]);
        len[id] = llen[id] = rlen[id] = 1;
        return;
    }
    int m = (l + r) >> 1;
    build(l,m,id<<1);
    build(m+1,r,id<<1|1);
    pushup(l, r, id);
}
int query(int ll, int rr, int l, int r, int id)
{
    if (ll <= l && r <= rr)
        return len[id];
    int m = (l + r) >> 1;
    if (ll <= m && m < rr)
    {
        int l1 = query(ll, rr, l,m,id<<1);
        int l2 = query(ll, rr, m+1,r,id<<1|1);
        if (tree[m] < tree[m + 1])
        {
            int le = max(ll, m - rlen[id << 1] + 1);
            int ri = min(rr, m + llen[id << 1 | 1]);
            return max(max(l1, l2), ri - le + 1);
        }
        return max(l1, l2);
    }
    else if (rr <= m)
        return query(ll, rr, l,m,id<<1);
    else
        return query(ll, rr, m+1,r,id<<1|1);
}

void update(int a, int b, int l, int r, int id)
{
    if (a == l && a == r)//找到要更新的位置
    {
        tree[a] = b;
        return;
    }
    int m = (l + r) >> 1;
    if (m >= a)
        update(a, b, l,m,id<<1);
    else
        update(a, b, m+1,r,id<<1|1);
    pushup(l, r, id);
}
int main()
{
    int t;
    scanf("%d\n", &t);
    while (t--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        build(0, n - 1, 1);

        while (m--)
        {
            char c[5];
            int a, b;
            scanf("%s %d %d", c, &a, &b);
            if (c[0] == ‘Q‘)
                printf("%d\n", query(a, b, 0, n - 1, 1));
            else
                update(a, b, 0, n - 1, 1);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/-citywall123/p/11066942.html

时间: 2024-10-09 05:44:59

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

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

http://acm.hdu.edu.cn/showproblem.php?pid=3308 学到两点: 1.以区间端点为开始/结束的最长......似乎在Dp也常用这种思想 2.分类的时候,明确标准逐层分类,思维格式: 条件一成立: { 条件二成立: { } else { } } else { 条件二成立: { } else { } } 上面的这种方式很清晰,如果直接想到那种情况iif(条件一 &条件二)就写,很容易出错而且把自己搞乱,或者情况不全,,,我就因为这WA了几次 3.WA了之后 ,

HDU 3308 线段树单点更新+区间查找最长连续子序列

LCIS                                                              Time Limit: 6000/2000 MS (Java/Others)                                                                 Memory Limit: 65536/32768 K (Java/Others)                                       

HDU 1754 I Hate It 线段树单点更新求最大值

题目链接 线段树入门题,线段树单点更新求最大值问题. #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #define N 200005 using namespace std; int data[N]; struct Tree { int l,r,ans; }tree[N*4]; void build(in

HDU 1394(线段树单点更新)

题意:就是给出一串数,当依次在将第一个数变为最后一个数的过程中,要你求它的最小逆序数. 思路:可以用树状数组和线段数做.这里我是用线段树做的.建的是一棵空树,然后每插入一个点之前,统计大于这个数的有多少个,直到所有的数都插入完成,就结果了逆序树的统计. 要得出答案主要是利用了一个结论,如果是0到n的排列,那么如果把第一个数放到最后,对于这个数列,逆序数是减少a[i],而增加n-1-a[i]的. #include<iostream> #include<cstring> #includ

HDU 4302 线段树单点更新,维护区间最大最小值

http://acm.hdu.edu.cn/showproblem.php?pid=4302 Problem Description Holedox is a small animal which can be considered as one point. It lives in a straight pipe whose length is L. Holedox can only move along the pipe. Cakes may appear anywhere in the p

HDU 1394 Minimum Inversion Number (线段树 单点更新 求逆序数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给你一个n个数的序列,其中组成的数只有0-n,我们可以进行这么一种操作:把第一个数移到最后一个,次数不限.问,在原始数列和最新生成的数列中逆序数最小可以是多少? 刚开始以为需要枚举求逆序数,但最后知道了这个题是有规律的:一个由0-n组成的n个数的数列,当第一个数移到最后一位的时候,整个数列的逆序数会减少x[i](移动前,后面比他小的),会增加n-x[i]-1(移动后,前面比他大的). 那

HDU 2795 Billboard (线段树单点更新 &amp;&amp; 求区间最值位置)

题意 : 有一块 h * w 的公告板,现在往上面贴 n 张长恒为 1 宽为 wi 的公告,每次贴的地方都是尽量靠左靠上,问你每一张公告将被贴在1~h的哪一行?按照输入顺序给出. 分析 : 这道题说明了每一次贴都尽量选择靠上靠左的位置,那既然这样,我们以1~h建立线段树,给每一个叶子节点赋值初值 w 表示当前行最大能够容纳宽度为 w 的公告纸,那么对于某一输入 wi 只要在线段树的尽量靠左的区间找出能够容纳这张公告的位置(即叶子节点)然后减去 wi 即可,需要对query()函数进行一点改造,将

HDU 2795 线段树单点更新

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 23498    Accepted Submission(s): 9687 Problem Description At the entrance to the university, there is a huge rectangular billboard of s

hdu 1166 线段树单点更新

等线段树复习完再做个总结 1101 2 3 4 5 6 7 8 9 10Query 1 3Add 3 6Query 2 7Sub 10 2Add 6 3Query 3 10End Case 1:63359 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue>