【解题报告】hdu3308 LCIS

http://acm.hdu.edu.cn/showproblem.php?pid=3308

大意:输入n个数,m个操作。操作有两种:1.U x y 将数组第x位变为y   2. Q x y 问数组第x位到第y位连续最长子序列的长度。

 

题目主要考察的就是对pushup逆向更新的运用,就是更改树底(1号操作),从树底下往上更新。。。

至于最长子序列,长度为1的区间最长子序列当然就是自己,对于两个区间的最长子序列合并,无非就是两种情况,一种就是两个区间的最长子序列接上了,第二种就是没接上,取两个最长子序列的最大值

我的程序,用a[i].l保存区间左端,a[i].r保存区间右端,a[i].c保存区间长度(就是l-r+1),a[i].ln保存区间里的最长子序列的左端有多大,a[i].rn保存区间里的最长子序列的右端有多大,a[i].ls保存最长子序列左端位置,a[i].rs保存最长子序列右端位置,a[i].ms保存最长子序列长度(就是a[i].rs-a[i].ls+1)

然后就是合并咯

 

我的程序(可能是优化不到位,能过很多数据但到hdu上评测会超时,也许过几天就能把这个括号删掉了)

#include <cstdio>  
#include <cstring>  
#include <algorithm>  
using namespace std;  
  
#define L 100010  
int n,m,s[L];  
  
struct node  
{  
    int l,r,c;
    int ln,rn;
    int ls,rs,ms;
} a[L<<2];  
  
void pushup(int i)  
{  
    a[i].ls = a[2*i].ls;  
    a[i].rs = a[2*i+1].rs;  
    a[i].ln = a[2*i].ln;  
    a[i].rn = a[2*i+1].rn;  
    a[i].ms = max(a[2*i].ms,a[2*i+1].ms);  
    if(a[2*i].rn<a[2*i+1].ln) 
    {  
        if(a[2*i].ls == a[2*i].c)  
            a[i].ls+=a[2*i+1].ls;  
        if(a[2*i+1].rs == a[2*i+1].c)  
            a[i].rs+=a[2*i].rs;  
        a[i].ms = max(a[i].ms,a[2*i].rs+a[2*i+1].ls);  
    }  
}  
  
void init(int l,int r,int i)
{  
    a[i].l=l;  
    a[i].r=r;  
    a[i].c=r-l+1;  
    if(l==r)  
    {  
        a[i].ln=a[i].rn=s[l];  
        a[i].ls=a[i].rs=a[i].ms=1;  
        return;  
    }  
    int k=(a[i].l+a[i].r)>>1;  
    init(l,k,2*i);  
    init(k+1,r,2*i+1);  
    pushup(i);  
}  
  
void insert(int i,int t,int m)  
{  
    if(a[i].l == a[i].r)  
    {  
        a[i].ln = a[i].rn = m;  
        return;  
    }  
    int k = (a[i].l+a[i].r)>>1;  
    if(t<=k)  
        insert(2*i,t,m);  
    if(t>k)  
        insert(2*i+1,t,m);  
    pushup(i);  
}  
  
int search(int l,int r,int i)
{  
    if(a[i].l>=l && a[i].r<=r)  
    {  
        return a[i].ms;  
    }  
    int k = (a[i].l+a[i].r)>>1,sum = 0;  
    if(l<=k) sum=max(sum,search(l,r,2*i));  
    if(r>k) sum=max(sum,search(l,r,2*i+1));  
    if(a[2*i].rn<a[2*i+1].ln)  
        sum = max(sum , min(k-l+1,a[2*i].rs)+min(r-k,a[2*i+1].ls));  
    return sum;  
}  
  
  
int main()  
{  
    int t,i,l,r;  
    char str[5];  
    scanf("%d",&t);  
    while(t--)  
    {  
        scanf("%d%d",&n,&m);  
        for(i=1; i<=n; i++)  
            scanf("%d",&s[i]);  
        init(1,n,1);  
        while(m--)  
        {  
            scanf("%s%d%d",str,&l,&r);  
            if(str[0] == 'Q')  
                printf("%d\n",search(l+1,r+1,1));  
            else  
                insert(1,l+1,r);  
        }  
    }  
  
    return 0;  
}  

 

转载于:https://www.cnblogs.com/hypercurve/p/6536127.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值