BZOJ 4553 [Tjoi2016&Heoi2016]序列

题解:我现在真的怀疑自己的语文水平

用f[i]表示以i为结尾的最长上升子序列

然后找前面的j转移

f[i]=max{f[j]}+1 (j<=i&&max[j]<=a[i]&&a[j]<=min[i])

这是偏序关系,用树套树或CDQ分治解决

//mx[j]<=a[i]
//a[j]<=mn[i]
#include<iostream>
#include<cstdio>
#include<cstring>
#define lo now<<1
#define ro now<<1|1
using namespace std;
const int maxn=100009;
const int lgn=30;

int n,m;
int ans=0;
int f[maxn]={0},mx[maxn],mn[maxn],v[maxn];

int nn=0;
int fa[maxn*lgn]={0},ch[maxn*lgn][2]={0},ky[maxn*lgn]={0},nowf[maxn*lgn]={0},mxf[maxn*lgn]={0};
int son(int x){
    if(ch[fa[x]][0]==x)return 0;
    else return 1;
}
void pushup(int x){
    mxf[x]=max(nowf[x],max(mxf[ch[x][0]],mxf[ch[x][1]]));
}

void Rotate(int &root,int x){
    int y=fa[x];
    int z=fa[y];
    int b=son(x),c=son(y);
    int a=ch[x][b^1];
    if(z)ch[z][c]=x;
    else root=x;
    fa[x]=z;
    if(a)fa[a]=y;
    ch[y][b]=a;
    fa[y]=x;ch[x][b^1]=y;
    pushup(y);pushup(x);
}
void Splay(int &root,int x,int i){
    while(fa[x]!=i){
        int y=fa[x];
        int z=fa[y];
        if(z==i){
            Rotate(root,x);
        }else{
            if(son(x)==son(y)){
                Rotate(root,y);Rotate(root,x);
            }else{
                Rotate(root,x);Rotate(root,x);
            }
        }
    }
}

void Ins(int &root,int p){
    int x=root,y=0;
    while(x){
        y=x;
        if(mx[p]<=ky[x]){
            x=ch[x][0];
        }else{
            x=ch[x][1];
        }
    }
    x=++nn;
    fa[x]=y;ky[x]=mx[p];nowf[x]=f[p];mxf[x]=nowf[x];
    if(!y){
        root=x;
    }else{
        if(ky[x]<=ky[y])ch[y][0]=x;
        else ch[y][1]=x;
    }
    Splay(root,x,0);
}

int Getmxf(int x,int val){
    int ret=0;
    while(x){
        if(ky[x]<=val){
            ret=max(ret,max(mxf[ch[x][0]],nowf[x]));
            x=ch[x][1];
        }else{
            x=ch[x][0];
        }
    }
    return ret;
}

struct SegmentTree{
    int l,r;
    int root;
}tree[maxn<<2];
void BuildTree(int now,int l,int r){
    tree[now].l=l;tree[now].r=r;tree[now].root=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    BuildTree(lo,l,mid);
    BuildTree(ro,mid+1,r);
}

void Insertpoint(int now,int pla,int p){
    Ins(tree[now].root,p);
    if(tree[now].l==tree[now].r)return;
    int mid=(tree[now].l+tree[now].r)>>1;
    if(pla<=mid)Insertpoint(lo,pla,p);
    else Insertpoint(ro,pla,p);
}

int Querymax(int now,int ll,int rr,int val){
    if(tree[now].l>=ll&&tree[now].r<=rr){
        return Getmxf(tree[now].root,val);
    }
    int mid=(tree[now].l+tree[now].r)>>1;
    int ret=0;
    if(ll<=mid)ret=max(ret,Querymax(lo,ll,rr,val));
    if(rr>mid)ret=max(ret,Querymax(ro,ll,rr,val));
    return ret;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&v[i]);
        mx[i]=mn[i]=v[i];
    }
    while(m--){
        int x,y;
        scanf("%d%d",&x,&y);
        mx[x]=max(mx[x],y);
        mn[x]=min(mn[x],y);
    }
    
    BuildTree(1,1,100000);
    
    for(int i=1;i<=n;++i){
        f[i]=Querymax(1,1,mn[i],v[i])+1;
        Insertpoint(1,v[i],i);
        ans=max(ans,f[i]);
    }
    
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-03-15 21:30  ws_zzy  阅读(173)  评论(0编辑  收藏  举报