佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可 。
注意:每种变化最多只有一个值发生变化。在样例输入1中,所有的变化是:
1 2 3
2 2 3
1 3 3
1 1 3
1 2 4
选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:
3 3 3
3 2 3
选择子序列为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要
输入格式:
输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。接下来一行有n个数,表示这个数列原始的状态。接下来m行,每行有2个数x, y,表示数列的第x项可以变化成y这个值。1 <= x <= n。
输出格式:
输出一个整数,表示对应的答案
输入样例#1:
3 4
1 2 3
1 2
2 3
2 1
3 4
输出样例#1:
3
对于20%数据所有数字均为正整数,且小于等于300
对于50%数据所有数字均为正整数,且小于等于3,000
对于100%数据所有数字均为正整数,且小于等于100,000
这道题是DP应该不难看出来。
dp[i]表示选择i以后所能形成的满足条件的子序列的最大值
转移的时候枚举前面的点(j)。
设MX[i]表示i号位置能变成的最大值,MI[i]表示i号位置能变成的最小值,a为原序列
这样转移的时候会有两个限制条件
a[i]>=MX[j]a[i]>=MX[j]&&MI[i]>=a[j]
这很明显是个二维偏序问题嘛,用CDQ树套树什么的都可以搞。
树套树的话,将a抽象为x轴,将MX抽象为y轴
转移的时候我们实际是在左下角为(0,0),右上角为MI[i],a[i]的矩阵中查最大值
每次转移对答案的贡献的话实际上只是改变了a[i],mx[i]的值
然后就能很自然的想到树套树了,线段树套线段树或者树状数组套线段树都可以搞
后者常数小一些
线段树的数组一定要开的足够大!!!!
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=6*1e6+10;
const int MAXNN=1e5+10;
const int INF=1e8+10;
inline int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int root[MAXN],N,M,MX[MAXNN],MI[MAXNN],a[MAXNN];
struct S
{
struct node
{
int ls,rs,mx;
}T[MAXN];
int tot;
int query(int now,int ll,int rr,int pos)
{
if(ll==rr)
return T[now].mx;
int mid=ll+rr>>1;
if(pos<=mid)
return query(T[now].ls,ll,mid,pos);
else
return max( T[T[now].ls].mx , query(T[now].rs,mid+1,rr,pos));
}
void change(int &now,int ll,int rr,int pos,int val)
{
if(!now) now=++tot;
T[now].mx=max(T[now].mx,val);
if(ll==rr) return ;
int mid=ll+rr>>1;
if(pos<=mid) change(T[now].ls,ll,mid,pos,val);
else change(T[now].rs,mid+1,rr,pos,val);
}
}tree;
struct B
{
int N;
int Tree[MAXNN];
int lowbit(int p) {return p&(-p);}
int Query(int k,int val)
{
int ans=0;
while(k)
{
ans=max(ans,tree.query(root[k],1,N,val));
k-=lowbit(k);
}
return ans;
}
void Change(int k,int pos,int val)
{
while(k<=N)
{
tree.change(root[k],1,N,pos,val);
k+=lowbit(k);
}
}
}BIT;
int main()
{
//freopen("heoi2016_seq.in","r",stdin);
//freopen("heoi2016_seq.out","w",stdout);
N=read();M=read();
for(int i=1;i<=N;i++) MX[i]=MI[i]=a[i]=read();
for(int i=1;i<=M;i++)
{
int x=read(),y=read();
MX[x]=max(MX[x],y);BIT.N=max(BIT.N,MX[x]);
MI[x]=min(MI[x],y);
}
int ans=0;
for(int i=1;i<=N;i++)
{
int now=BIT.Query(MI[i],a[i])+1;
BIT.Change(a[i],MX[i],now);
ans=max(ans,now);
}
printf("%d",ans);
return 0;
}