[HEOI/TJOI2016]序列

Description:

给你一个序列,每个数可能变化为另一个数,每次最多有一个数变化

求最长的子序列,无论如何变化,这个子序列都不下降

Hint:

\(n \le 10^5\)

Solution:

没想到是dp

设f[i]表示以i结尾的最长长度,有:

\[f[i]=f[j]+1\]

\[当max_j<val_i,val_j<min_i\]

然后cdq直接搞一波,注意排序那里要魔改一下

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=2e5+5,inf=1e9;
int n,m,cnt,f[mxn],tr[mxn],hd[mxn];

inline int read() {
    char c=getchar(); int x=0,f=1;
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
    return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}

struct ed {
    int to,nxt;
}t[mxn<<1];

inline void add(int u,int v) {
    t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}

struct Q {
    int val,mx,mi,id;
}T[mxn];

int cmpv(Q x,Q y) {
    return x.val<y.val;
}

int cmpm(Q x,Q y) {
    return x.mx<y.mx;
}

int cmpi(Q x,Q y) {
    return x.id<y.id;
}

void mod(int x,int y,int opt) {
    while(x<=n) {
        if(opt) chkmax(tr[x],y);
        else tr[x]=-inf;
        x+=(x&-x);
    }
}

int query(int x) {
    int res=-inf;
    while(x) {
        chkmax(res,tr[x]);
        x-=(x&-x);
    }
    return res;
}

void cdq(int l,int r) {
    if(l==r) return ;
    int mid=(l+r)>>1;
    cdq(l,mid);
    sort(T+l,T+mid+1,cmpm);
    sort(T+mid+1,T+r+1,cmpv);
    int pos=l; //这里写错了几次
    for(int i=mid+1;i<=r;++i) { 
        while(T[pos].mx<=T[i].val&&pos<=mid) 
            mod(T[pos].val,f[T[pos].id],1),++pos;
        chkmax(f[T[i].id],query(T[i].mi)+1);    
    }
    for(int i=l;i<pos;++i) mod(T[i].val,0,0);
    sort(T+l,T+r+1,cmpi); //dp型cdq千万别忘记重排
    cdq(mid+1,r);   
}

int main()
{
    n=read(); m=read(); int x,y; memset(tr,0x80,sizeof(tr));
    for(int i=1;i<=n;++i) T[i].val=T[i].mx=T[i].mi=read(),T[i].id=i;
    for(int i=1;i<=m;++i) {
        x=read(); y=read();
        chkmin(T[x].mi,y);
        chkmax(T[x].mx,y);
    }
    for(int i=1;i<=n;++i) f[i]=1; 
    cdq(1,n); int ans=0;
    for(int i=1;i<=n;++i) chkmax(ans,f[i]);
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/list1/p/10637651.html