Description
佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。
玩具上有一个数列,数列中某些项的值可能会变化,
她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可
注意:每种变化最多只有一个值发生变化。
在样例输入1中,所有的变化是:
1 2 3
2 2 3
1 3 3
1 1 3
1 2 4
选择子序列为原序列,即在任意一种变化中均为不降子序列
在样例输入2中,所有的变化是:
3 3 3
3 2 3
选择子序列为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求
Input
输入的第一行有两个正整数n, m
分别表示序列的长度和变化的个数。
接下来一行有n个数,表示这个数列原始的状态。
接下来m行,每行有2个数x, y,
表示数列的第x(
1≤x≤n
)项可以变化成y这个值
所有数字均为正整数,且小于等于
105
Output
输出一个整数,表示对应的答案
Sample Input
3 4
1 2 3
1 2
2 3
2 1
3 4
Sample Output
3
首先自然想到对于每一个位置
只有变化的最大值和最小值
对它造成影响
对于位置i,把它们分别记做
MAXi
和
MINi
,i位置的值记做
vi
考虑Dp
f[i]=max(f[j]+1)
0≤j<i,MAXj≤vi,vj≤MINi
可以用二维数据结构优化
也可以CDQ分治
考虑 [l,mid] 对 [mid,r] 的贡献
排一波序然后数据结构维护
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
char ch;
int fl;
inline void read(int &a){
for(fl=1,ch=getchar();ch<'0'||ch>'9';ch=getchar()) if (ch=='-') fl=-fl;
for(a=0;ch>='0'&&ch<='9';ch=getchar()) a=(a<<3)+(a<<1)+(ch^'0');
a*=fl;
}
const int Maxn=1e5+10;
struct Ques{
int x,y,id;
bool operator <(const Ques &A)const{return x!=A.x?x<A.x:id<A.id;}
}G[Maxn];
int c[Maxn],MAXN[Maxn],MINN[Maxn],Val[Maxn],F[Maxn];
inline void Add(int x,int v){for(int i=x;i<=Maxn;i+=i&(-i)) c[i]=max(c[i],v);}
inline void Clear(int x){for(int i=x;i<=Maxn;i+=i&(-i)) c[i]=0;}
inline int Qry(int x){ int Ans=0;for(int i=x;i;i-=i&(-i)) Ans=max(Ans,c[i]);return Ans;}
void CDQ(int l,int r){
int mid=(l+r)>>1;
if(l==r){F[mid]=max(F[mid],1);return;}
CDQ(l,mid);
for(int i=l;i<=r;i++)G[i].id=i;
for(int i=l;i<=mid;i++)G[i].x=MAXN[i],G[i].y=Val[i];
for(int i=mid+1;i<=r;i++)G[i].x=Val[i],G[i].y=MINN[i];
sort(G+l,G+r+1);
for(int i=l;i<=r;i++){
if (G[i].id<=mid) Add(G[i].y,F[G[i].id]);
else F[G[i].id]=max(F[G[i].id],Qry(G[i].y)+1);
}
for(int i=l;i<=r;i++)
if (G[i].id<=mid)Clear(G[i].y);
CDQ(mid+1,r);
}
int main(){
int n,m,i,Ans=0,x,y;
read(n);read(m);
for(i=1;i<=n;i++)read(Val[i]),MAXN[i]=MINN[i]=Val[i];
for(i=1;i<=m;i++){
read(x);read(y);
MAXN[x]=max(MAXN[x],y);MINN[x]=min(MINN[x],y);
}
CDQ(1,n);
for(i=1;i<=n;i++)Ans=max(Ans,F[i]);
printf("%d",Ans);
return 0;
}