HDU 3308 LCIS

线段树区间合并

/* ***********************************************
Author        :Zhou Zhentao
Email         :[email protected]
Created Time  :2015/11/28 9:05:25
File Name     :main.cpp
************************************************ */

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;

const int maxn=100000+10;
struct SegTree
{
    int lsum,rsum,msum;
    int lnum,rnum;
}segTree[4*maxn];
int T,N,Q;

void pushUp(int rt,int len)
{
    //确定左边第一个数字
    segTree[rt].lnum=segTree[2*rt].lnum;

    //确定右边第一个数字
    segTree[rt].rnum=segTree[2*rt+1].rnum;

    //确定从左开始的最长连续上升的长度
    if(segTree[2*rt].msum==len-len/2&&segTree[2*rt].rnum<segTree[2*rt+1].lnum)
        segTree[rt].lsum=segTree[2*rt].lsum+segTree[2*rt+1].lsum;
    else segTree[rt].lsum=segTree[2*rt].lsum;

    //确定从右开始的最长连续上升的长度
    if(segTree[2*rt+1].msum==len/2&&segTree[2*rt].rnum<segTree[2*rt+1].lnum)
        segTree[rt].rsum=segTree[2*rt].rsum+segTree[2*rt+1].rsum;
    else segTree[rt].rsum=segTree[2*rt+1].rsum;

    //确定区间最长连续上升的长度
    segTree[rt].msum=max(segTree[2*rt].msum,segTree[2*rt+1].msum);
    if(segTree[2*rt].rnum<segTree[2*rt+1].lnum)
        segTree[rt].msum=max(segTree[rt].msum,segTree[2*rt].rsum+segTree[2*rt+1].lsum);
}

void build(int l,int r,int rt)
{
    if(l==r)
    {
        scanf("%d",&segTree[rt].lnum);
        segTree[rt].rnum=segTree[rt].lnum;
        segTree[rt].lsum=segTree[rt].rsum=segTree[rt].msum=1;
        return ;
    }

    int m=(l+r)/2;
    build(l,m,rt*2);
    build(m+1,r,rt*2+1);

    pushUp(rt,r-l+1);
}

void update(int p,int add,int l,int r,int rt)
{
    if(l==r)
    {
        segTree[rt].lnum=add;
        segTree[rt].rnum=add;
        return;
    }

    int m=(l+r)/2;
    if(p<=m) update(p,add,l,m,2*rt);
    else update(p,add,m+1,r,2*rt+1);

    pushUp(rt,r-l+1);
}

int quary(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    {
        return segTree[rt].msum;
    }
    int m=(l+r)/2;
    if(R<=m) return quary(L,R,l,m,2*rt);
    else if(L>=m+1) return quary(L,R,m+1,r,2*rt+1);
    else
    {
        int Q1=quary(L,R,l,m,2*rt);
        int Q2=quary(L,R,m+1,r,2*rt+1);

        int ans=max(Q1,Q2);

        int Min1=min(segTree[2*rt].rsum,m-L+1);
        int Min2=min(segTree[2*rt+1].lsum,R-m);

        if(segTree[2*rt].rnum<segTree[2*rt+1].lnum)
            ans=max(ans,Min1+Min2);
        return ans;
    }

}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&Q);

        build(1,N,1);

        for(int i=1;i<=Q;i++)
        {
            char op[5];
            int x,y;
            scanf("%s",op);

            if(op[0]==‘Q‘)
            {
                scanf("%d%d",&x,&y);
                printf("%d\n", quary(x+1,y+1,1,N,1));
            }

            else if(op[0]==‘U‘)
            {
                scanf("%d%d",&x,&y);
                update(x+1,y,1,N,1);
            }
        }
    }
    return 0;
}
时间: 2024-10-12 20:04:06

HDU 3308 LCIS的相关文章

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 3308 LCIS (端点更新+区间合并)

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

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

HDU 3308 LCIS 线段树 区间更新

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目描述: 有两种操作, U x y  , 第xth赋值为y .Q x y , 查询区间x-y的最长连续上升子序列的长度L 解题思路: 对于线段树不好的我依然好难.....有太多细节需要注意了....但是这是一道很好的题, 一段区间的L可能从三个地方来, 一种是中间, 一种是以左起点为开头的, 一种是以右起点结尾的, 这样查询的时候就要注意了: 如果两段的中间值是a[m] < a[m+1]

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 题意:给定n个数.2种操作. 更新第a个数为b. 查询区间[a,b]的最长连续上升子序列. 思路:裸的区间合并.每个结点存 从区间左端点开始的最长连续上升子序列的长度lm. 以区间右端点结束的最长连续上升子序列的长度rm. 区间的最长连续上升子序列的长度mx. 区间左端点的数值la. 区间右端点的数值ra. 代码: #include <iostream> #include <stdio

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, indicat

线段树 [HDU 3308] LCIS

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

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

题目传送:LCIS 线段树,区间合并,一次过啦,没有纠结,这几天过的最愉快的一个题 思路:求最长连续上升子序列,外带单点更新,经典的线段树题目.具体看代码注释 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack>