BZOJ 2090 [Poi2010]Monotonicity 2 DP+线段树

题意:
给出N个正整数a[1..N],再给出K个关系符号(>、<或=)s[1..k]。
选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。
求出L的最大值。
解析:
一眼考虑DP,不过这个DP我的确刚开始认为这是没有什么正确性的,然后我就不会辣,但是大家都说这题就是DP..
并且好像自己一顿想要构造也没有构造出来不合法的数据?
那我就只能回到自己刚开始的DP思路了。
设F[i]表示到第i位拿出来的最长序列长度。
所以下一个符号显然是确定的。
然后等于号的话,我们直接开一个数组记录哪一个值上一次出现的可行位置即可。
小于号,丢到线段树里面,线段树对权值开,记录一段权值区间最大的已出现的f值,查询直接拿最大就好了。
大于号同理,再开一个线段树丢进去即可。
F[i]=max(F[j]+1 并且 i,j 满足 F[j] 对应的大小关系 )
复杂度,查询O(1),插入 O(log106)
最坏 O(nlogn)
代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 500100
#define M 1000100
#define MM 1000000
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1 
using namespace std;
int n,k;
int a[N];
int next[M];
int app[M];
int f[N],can[M];
char s[N];
char tmp[2];
int ma[M<<2],pos[M<<2],ma2[M<<2],pos2[M<<2];
void pushup(int rt)
{
    ma[rt]=ma[rt<<1],pos[rt]=pos[rt<<1];
    if(ma[rt<<1|1]>ma[rt])
        ma[rt]=ma[rt<<1|1],pos[rt]=pos[rt<<1|1];
}
void update(int p,int v,int l,int r,int rt)
{
    if(l==r)
    {
        ma[rt]=v;
        pos[rt]=l;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)update(p,v,lson);
    else update(p,v,rson);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return rt;
    }
    int ret=0;
    int mid=(l+r)>>1;
    if(L<=mid)
    {
        int tmp=query(L,R,lson);
        if(ma[tmp]>=ma[ret])ret=tmp; 
    }
    if(R>mid)
    {
        int tmp=query(L,R,rson);
        if(ma[tmp]>ma[ret])ret=tmp;
    }
    pushup(rt);
    return ret;
}
void pushup2(int rt)
{
    ma2[rt]=ma2[rt<<1],pos2[rt]=pos2[rt<<1];
    if(ma2[rt<<1|1]>ma2[rt])
        ma2[rt]=ma2[rt<<1|1],pos2[rt]=pos2[rt<<1|1];
}
void update2(int p,int v,int l,int r,int rt)
{
    if(l==r)
    {
        ma2[rt]=v;
        pos2[rt]=l;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)update2(p,v,lson);
    else update2(p,v,rson);
    pushup2(rt);
}
int query2(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return rt;
    }
    int ret=0;
    int mid=(l+r)>>1;
    if(L<=mid)
    {
        int tmp=query2(L,R,lson);
        if(ma2[tmp]>=ma2[ret])ret=tmp; 
    }
    if(R>mid)
    {
        int tmp=query2(L,R,rson);
        if(ma2[tmp]>ma2[ret])ret=tmp;
    }
    pushup2(rt);
    return ret;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),app[a[i]]=n+1;
    for(int i=n;i>=1;i--)next[a[i]]=app[a[i]],app[a[i]]=i;
    for(int i=1;i<=k;i++)
    {
        scanf("%s",tmp);
        s[i]=tmp[0];
    }
    f[1]=1;
    if(s[1]=='<')update(a[1],1,1,MM,1);
    else if(s[1]=='>')update2(a[1],1,1,MM,1);
    else can[a[1]]=1;
    for(int i=2;i<=n;i++)
    {
        if(can[a[i]])
            f[i]=f[can[a[i]]]+1;
        int tmp=0;
        if(a[i]>1)
            tmp=query(1,a[i]-1,1,MM,1);
        if(ma[tmp]+1>f[i])
            f[i]=ma[tmp]+1;
        tmp=0;
        if(a[i]<1000000)
            tmp=query2(a[i]+1,MM,1,MM,1);
        if(ma2[tmp]+1>f[i])
            f[i]=ma2[tmp]+1;
        if(s[(f[i]-1)%k+1]=='<')update(a[i],f[i],1,MM,1);
        else if(s[(f[i]-1)%k+1]=='>')update2(a[i],f[i],1,MM,1);
        else can[a[i]]=i;
    }
    int ans=0;
    for(int i=1;i<=n;i++)ans=max(ans,f[i]);
    printf("%d\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值