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

来源:互联网 发布:商业公司顶级域名是 编辑:程序博客网 时间:2024/05/16 14:22

题意:
给出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 0
原创粉丝点击