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 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<=10 5).
The next line has n integers(0<=val<=10 5).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=10 5)
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
 

Author
shǎ崽
 

Source
HDOJ Monthly Contest – 2010.02.06
 

Recommend
wxl   |   We have carefully selected several similar problems for you:   3397  1542  1828  2871  1255 
 

题目大意:给n个数,m个操作。两种操作:Q a b 表示查询【a,b】这个区间的LCIS(即最长连续递增子序列)的长度。U a b 表示更新第a个数把他变成b(从0开始)。

解题思路:主要解决简单的单点更新和区间的查询,区间记录最长的连续递增子序列长度。要分析清楚各种情况。

详见代码。
#include <iostream>
#include <cstdio>

using namespace std;

struct node
{
    int l,r;
    int mmax;
    int lmax,rmax;
    int lnum,rnum;
}s[100000*4+10];

void InitTree(int l,int r,int k)
{
    s[k].l=l;
    s[k].r=r;
    s[k].mmax=1;
    s[k].rmax=1;
    s[k].lmax=1;
    s[k].lnum=s[k].rnum=0;
    if (l==r)
        return ;
    int mid=(l+r)/2;
    InitTree(l,mid,2*k);
    InitTree(mid+1,r,2*k+1);
}

void UpdataTree(int i,int change,int k)
{
    if (s[k].l==s[k].r&&s[k].l==i)
    {
        s[k].lnum=s[k].rnum=change;
        return ;
    }
    int mid=(s[k].l+s[k].r)/2;
    if (i>mid)
        UpdataTree(i,change,2*k+1);
    else if (i<=mid)
        UpdataTree(i,change,2*k);

    s[k].lnum=s[k*2].lnum;
    s[k].rnum=s[k*2+1].rnum;

    s[k].lmax=s[k*2].lmax;
    s[k].rmax=s[k*2+1].rmax;

    s[k].mmax=max(s[k*2].mmax,s[k*2+1].mmax);
    if(s[k*2].rnum<s[k*2+1].lnum)
    {
        s[k].mmax=max(s[k].mmax,s[k*2].rmax+s[k*2+1].lmax);
        if(s[k*2].lmax==s[k*2].r-s[k*2].l+1)
            s[k].lmax=s[k*2].lmax+s[k*2+1].lmax;
        if(s[k*2+1].rmax==s[k*2+1].r-s[k*2+1].l+1)
            s[k].rmax=s[k*2].rmax+s[k*2+1].rmax;
    }
}

int SearchTree(int l,int r,int k)
{
    if (s[k].l==l&&s[k].r==r)
        return s[k].mmax;
    else
    {
        int mid=(s[k].l+s[k].r)/2;
        if (l>mid)
            return SearchTree(l,r,2*k+1);
        else if (r<=mid)
            return SearchTree(l,r,2*k);
        /*else
        {
            if (s[k].lnum<s[k].rnum)
                return SearchTree(l,mid,2*k)+SearchTree(mid+1,r,2*k+1);
            else if
        }*/
        else
        {
            int a=min(s[k*2].rmax,mid-l+1);
            int b=min(s[k*2+1].lmax,r-mid);
            int Max=max(a,b);
            Max=max(Max,SearchTree(l,mid,2*k));
            Max=max(Max,SearchTree(mid+1,r,2*k+1));
            if(s[k*2].rnum<s[2*k+1].lnum)
            {
                Max=max(Max,a+b);
            }
            return Max;
        }

    }
}

int main()
{
    int t;
    char ch[70];
    scanf("%d",&t);
    while (t--)
    {
        int n,m,w,a,b;
        scanf("%d%d",&n,&m);
        InitTree(0,n-1,1);
        for (int i=0; i<n; i++)
        {
            scanf("%d",&w);
            UpdataTree(i,w,1);
        }
        for (int i=0; i<m; i++)
        {
            //getchar();
            scanf("%s%d%d",ch,&a,&b);
            if (ch[0]=='Q')
            {
                //cout<<"!!!!!!!!!!!!!!!!!"<<endl;
                int ans=SearchTree(a,b,1);
                printf ("%d\n",ans);

            }
            else if (ch[0]=='U')
            {
                UpdataTree(a,b,1);
            }
        }
    }
    return 0;
}



你可能感兴趣的:(算法,C语言,合并)