题解:我现在真的怀疑自己的语文水平
用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 ",ans); return 0; }