当前位置:编程学习 > C/C++ >>

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

题意:给一个序列,有两种操作,Q:询问x到y的LCIS长度。U:将序号为x的值改为y。
思路:用线段树来维护序列,每次更改值时就更新树,查询是很快的,查询时要注意。
 
 
 
 
 
 
#include<stdio.h>  
#include<string.h>  
const int N=100100;  
int a[N];  
struct Tree  
{  
    int L,R,ml;  
    int Ll,Rl,Ln,Rn;  
    //ml区间的LCIS长度  
    //Ll,Rl区间左边右边的LCIS长度  
    //Ln,Rn区间左右的值  
}T[N*3];  
int max(int a,int b)  
{  
    if(a>b)return a;  
    return b;  
}  
int min(int a,int b)  
{  
    if(a<b)return a;  
    return b;  
}  
void buildTree(int L,int R,int id)  
{  
    T[id].L=L;T[id].R=R;  
    if(L==R)  
    {  
        T[id].Ln=T[id].Rn=a[L];  
        T[id].ml=T[id].Ll=T[id].Rl=1;  
        return ;  
    }  
    int mid=(L+R)>>1,li=id<<1,ri=li+1;  
    buildTree(L,mid,id<<1);  
    buildTree(mid+1,R,id<<1|1);  
    T[id].Ln=T[li].Ln;T[id].Rn=T[ri].Rn;  
    T[id].Ll=T[li].Ll;T[id].Rl=T[ri].Rl;  
    T[id].ml=max(T[li].ml,T[ri].ml);  
    if(T[li].Rn<T[ri].Ln)//左区间和右区间可以合并  
    {  
        T[id].ml=max(T[id].ml,T[li].Rl+T[ri].Ll);  
        if(T[li].Rl==mid-T[li].L+1)//左区间整个区间是LCIS,更新该区间的左边LCIS长度。  
            T[id].Ll=T[li].Ll+T[ri].Ll;  
        if(T[ri].Rl==T[ri].R-mid)  
            T[id].Rl=T[li].Rl+T[ri].Rl;           
    }  
}  
void insert(int LR,int w,int id)  
{  
    if(T[id].L==T[id].R)  
    {  
        T[id].Ln=T[id].Rn=w;  
        return ;  
    }  
    int mid=(T[id].L+T[id].R)>>1,li=id<<1,ri=li+1;  
    if(LR<=mid)insert(LR,w,li);  
    else insert(LR,w,ri);  
    T[id].Ln=T[li].Ln;T[id].Rn=T[ri].Rn;  
    T[id].Ll=T[li].Ll;T[id].Rl=T[ri].Rl;  
    T[id].ml=max(T[li].ml,T[ri].ml);  
    if(T[li].Rn<T[ri].Ln)  
    {  
        T[id].ml=max(T[id].ml,T[li].Rl+T[ri].Ll);  
        if(T[li].Rl==mid-T[li].L+1)  
            T[id].Ll=T[li].Ll+T[ri].Ll;  
        if(T[ri].Rl==T[ri].R-mid)  
            T[id].Rl=T[li].Rl+T[ri].Rl;           
    }  
}  
int query(int L,int R,int id)  
{  
    if(T[id].L==L&&T[id].R==R)  
        return T[id].ml;  
    int mid=(T[id].L+T[id].R)>>1,li=id<<1,ri=li+1;  
    if(mid>=R)  
        return query(L,R,li);  
    else if(mid<L) return query(L,R,ri);  
    else   
    {  
        int ls=query(L,mid,li);  
        int rs=query(mid+1,R,ri);  
        int ps=0;  
        if(T[li].Rn<T[ri].Ln)//左右两区间可以合并  
            ps=min(mid-L+1,T[li].Rl)+min(R-mid,T[ri].Ll);//合并的长度  
        return max(ps,max(ls,rs));  
    }  
}  
int main()  
{  
    int i,x,y,n,m,t;  
    char str[10];  
    scanf("%d",&t);  
    while(t--)  
    {  
        scanf("%d%d",&n,&m);  
        for(i=1;i<=n;i++)  
            scanf("%d",&a[i]);  
        buildTree(1,n,1);  
        while(m--)  
        {  
            scanf("%s%d%d",str,&x,&y);  
            if(str[0]=='Q')  
                printf("%d\n",query(x+1,y+1,1));  
            else insert(x+1,y,1);                 
        }  
    }  
    return 0;  
}  

 

 
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,