hdu4604 Deque,树状数组,最长上升/下降子序列

6 篇文章 0 订阅
hdu 4604 Deque,树状数组,最长上升/下降子序列

正在补习13多校题。

给你一组数,按顺序取出来,再给一个deque,按顺序把这组数取出来插到deque中,可以插头和尾,也可以直接丢掉。
要求deque中元素非降。
问deque中元素最多有多少个。

只要枚举一个中心点,然后就是找这个点之后的大于这个元素的最长上升序列和小于这个元素的下降序列的长度和+1,更新答案即可。

这里有一个蛋疼的地方,数组中元素是可能重复的(看样例还以为1到n,尼玛),还需要离散化。
而且不能简单的选大于等于和小于等于的数的和。

这样,从后面往前面做,i=n..1,设第i个点值为v
可能更新答案的只有
([v+1..n]中上升序列长度最长的)+([1..v]中下降序列长度最长的)+1
([v..n]中上升序列长度最长的)+([1..v-1]中下降序列长度最长的)+1
这两种。
这样可以省去找最长点的位置。

至于找[1..v]间的最大值,用树状数组简短实用。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define NN 101000
#define lowbit(x) (x&(-x))

int c[2][NN];
int ans,n;
int a[NN];
int b[NN];
int tn;

int bsch(int l,int r,int val){
    int m;
    while(l<=r){
        m=l+r>>1;
        if (val==b[m]) return m;
        else if (val<b[m]){
            r=m-1;
        }
        else l=m+1;
    }
}

int getmax(int pos,int c[]){
    int ret=0;
    while(pos){
        ret=max(ret,c[pos]);
        pos=pos-lowbit(pos);
    }
    return ret;
}

void add(int pos,int val,int c[]){
    while(pos<=n){
        c[pos]=max(c[pos],val);
        pos+=lowbit(pos);
    }
}

void work(int i){
    int v,m0,m1,m2,m3;
    v=a[i];
    m0=getmax(v-1,c[0]);
    m1=getmax(n-v,c[1]);
    m2=getmax(v,c[0]);
    m3=getmax(n+1-v,c[1]);
    ans=max(m0+m3+1,ans);
    ans=max(m1+m2+1,ans);
    add(v,m2+1,c[0]);
    add(n+1-v,m3+1,c[1]);
    
}

int main(){
    //freopen("4604in.txt","r",stdin);
    int cas,i;
    scanf("%d",&cas);
    while(cas--){
        scanf("%d",&n);
        for(i=1;i<=n;++i){
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        tn=1;
        sort(b+1,b+n+1);
        for(i=2;i<=n;++i){
            if (b[i]!=b[i-1]) b[++tn]=b[i];
        }

        for(i=1;i<=n;++i){
            a[i]=bsch(1,tn,a[i]);
        }

        ans=0;
        memset(c,0,sizeof(c));
        for(i=n;i>=1;--i){
            work(i);
        }
        printf("%d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值