hdoj 3308 LCIS 【线段树单点更新 + 区间合并】【求解最长递增序列 的长度】

来源:互联网 发布:零基础学云计算 编辑:程序博客网 时间:2024/05/26 09:54



LCIS

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5606    Accepted Submission(s): 2447


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
110 107 7 3 3 5 9 9 8 1 8 Q 6 6U 3 4Q 0 1Q 0 5Q 4 7Q 3 5Q 0 2Q 4 6U 6 10Q 0 9
 

Sample Output
11423125
 



题意:给你n个数组成的序列(序列中编号从0到n-1),有q次操作。

操作1——Q a  b,让你输出区间[a, b]里面最长的连续递增序列的长度;

操作2——U a  b,修改序列第a个数为b。


线段树单点更新 + 区间合并,重在PushUp函数的操作 和 查询操作。


AC代码:


#include <cstdio>#include <cstring>#include <algorithm>#define MAXN 100000+10#define lson o<<1, l, mid#define rson o<<1|1, mid+1, r#define ll o<<1#define rr o<<1|1using namespace std;struct Tree{    int l, r, len;//区间左右端点 和 长度    int lv, rv;//区间左端点的值  右端点的值    int lsum, rsum;//以区间左端点为起点的最长递增序列长度 以区间右端点为终点的最长递增序列长度    int sum;//区间 最长递增序列长度};Tree tree[MAXN<<2];void PushUp(int o){    tree[o].lv = tree[ll].lv;//左子树的左端点值    tree[o].rv = tree[rr].rv;//右子树的右端点值    tree[o].lsum = tree[ll].lsum;    tree[o].rsum = tree[rr].rsum;    tree[o].sum = max(tree[ll].sum, tree[rr].sum);    if(tree[ll].rv < tree[rr].lv)    {        if(tree[ll].lsum == tree[ll].len)//左半区间完全容纳最长递增序列 向右延伸            tree[o].lsum += tree[rr].lsum;        if(tree[rr].rsum == tree[rr].len)//右半区间完全容纳最长递增序列 向左延伸            tree[o].rsum += tree[ll].rsum;        //更新  左子树的右端点连续长度 + 右子树的左端点的连续长度        tree[o].sum = max(tree[o].sum, tree[ll].rsum + tree[rr].lsum);//更新最值    }}int a;void build(int o, int l, int r)//建树{    tree[o].l = l, tree[o].r = r;    tree[o].len = r -l + 1;    if(l == r)    {        scanf("%d", &a);        tree[o].lv = tree[o].rv = a;        tree[o].lsum = tree[o].rsum = tree[o].sum = 1;        return ;    }    int mid = (l + r) >> 1;    build(lson);    build(rson);    PushUp(o);}int query(int o, int L, int R){    if(L <= tree[o].l && R >= tree[o].r)        return tree[o].sum;    int mid = (tree[o].l + tree[o].r) >> 1;    int ans = 0;    if(L <= mid)//更新左子树        ans = max(ans, query(ll, L, R));    if(R > mid)//更新右子树        ans = max(ans, query(rr, L, R));    if(tree[ll].rv < tree[rr].lv)//更新最大值  注意要取最小段 不能超过要查询的区间        ans = max(ans, min(mid-L+1, tree[ll].rsum) + min(R-mid, tree[rr].lsum));    return ans;}void update(int o, int pos, int val){    if(tree[o].l == tree[o].r)//修改    {        tree[o].lv = tree[o].rv = val;        return ;    }    int mid = (tree[o].l + tree[o].r) >> 1;    if(pos <= mid)        update(ll, pos, val);    else        update(rr, pos, val);    PushUp(o);//维护 上传}int main(){    int t;    int n, q;    scanf("%d", &t);    while(t--)    {        scanf("%d%d", &n, &q);        build(1, 0, n-1);//建树        char str[5];        int a, b;        while(q--)        {            scanf("%s%d%d", str, &a, &b);            if(str[0] == 'Q')                printf("%d\n", query(1, a, b));            else                update(1, a, b);        }    }    return 0;}



0 0