【[HEOI2016/TJOI2016]序列】
压行真漂亮
首先这肯定是一个\(dp\)了
设\(dp_i\)表示\(i\)结尾的最长不下降子序列的长度
显然我们要找一个\(j\)来转移
也就是\(dp_i=max(dp_j+1)\)
那么什么样的\(j\)满足条件呢
首先得是\(j<i\)
我们还注意到一个条件就是这个序列里最多也只有一个位置会发生变化
可能是\(i\)这个位置发生变化,那么显然需要满足对于任意的\(a_i\)都需要满足大于等于\(val_j\)
于是就有\(val_j<=min_i\)
自然也有可能是前面的\(j\)发生变化,显然就是\(max_j<=val_i\)
之后这就是一个三维偏序了,\(CDQ\)分治就可以啦
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define re register
#define lowbit(x) ((x)&(-x))
#define maxn 100005
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,m,M;
int c[maxn];
inline void add(int x,int val) {for(re int i=x;i<=M;i+=lowbit(i)) c[i]=max(c[i],val);}
inline void clear(int x) {for(re int i=x;i<=M;i+=lowbit(i)) c[i]=0;}
inline int ask(int x) {int now=0;for(re int i=x;i;i-=lowbit(i)) now=max(c[i],now);return now;}
struct Point {int x,y,rk,ans,v;}a[maxn];
inline int cmp1(Point A,Point B) {return A.x<B.x;}
inline int cmp2(Point A,Point B) {return A.v<B.v;}
inline int cmp3(Point A,Point B) {return A.rk<B.rk;}
void CDQ(int s,int t)
{
if(s==t) return;
int mid=s+t>>1;
CDQ(s,mid),std::sort(a+s,a+mid+1,cmp2),std::sort(a+mid+1,a+t+1,cmp1);
int i=s,j=mid+1;
while(i<=mid&&j<=t)
if(a[i].v<=a[j].x) add(a[i].y,a[i].ans),i++;
else {int now=ask(a[j].v)+1;a[j].ans=max(a[j].ans,now),j++;}
while(j<=t) {int now=ask(a[j].v)+1;a[j].ans=max(a[j].ans,now),j++;}
for(re int k=s;k<i;k++) clear(a[k].y);
std::sort(a+mid+1,a+t+1,cmp3);CDQ(mid+1,t);
}
int main()
{
n=read(),m=read();
int A,B; for(re int i=1;i<=n;i++) a[i].x=a[i].y=read(),M=max(M,a[i].x),a[i].rk=i,a[i].ans=1,a[i].v=a[i].x;
for(re int i=1;i<=m;i++) A=read(),B=read(),a[A].y=max(a[A].y,B),M=max(M,a[A].y),a[A].x=min(a[A].x,B);
CDQ(1,n);int tot=0;for(re int i=1;i<=n;i++) tot=max(tot,a[i].ans);printf("%d\n",tot);
return 0;
}