题意:
玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可。每种变化最多只有一个值发生变化。
题解:
设Max[i]为a[i]可能变成的最大值,Min[i]为a[i]可能变成的最小值(Max[i]和Min[i]均包括a[i]本身)。那么i,j(i
这样我们就可以dp了,f[i]表示以i结尾的最长合法序列,那么f[i]=f[j]+1(j满足上述条件)。这实际上是一个三维偏序,所以可以使用树套树维护,外层为a[i],内层为Max[i],使用树状数组套线段树维护即可解决问题。
#include
#include
#include
using namespace std;
const int INF=100000;
int n,m,a[100002],Max[100002],Min[100002],rt[100002],cnt,f[100002],ans;
typedef struct{
int ls,rs,Max;
}P;
P p[10000002];
void gengxin(int root,int begin,int end,int wz,int z){
if (begin>wz || endreturn;
if (begin==end)
{
p[root].Max=max(p[root].Max,z);
return;
}
int mid=(begin+end)/2;
if (wz<=mid)
{
if (!p[root].ls)p[root].ls=++cnt;
gengxin(p[root].ls,begin,mid,wz,z);
}
else
{
if (!p[root].rs)p[root].rs=++cnt;
gengxin(p[root].rs,mid+1,end,wz,z);
}
p[root].Max=max(p[p[root].ls].Max,p[p[root].rs].Max);
}
int chaxun(int root,int begin,int end,int begin2,int end2){
if (!root || begin>end2 || endreturn 0;
if (begin>=begin2 && end<=end2)return p[root].Max;
int mid=(begin+end)/2;
return max(chaxun(p[root].ls,begin,mid,begin2,end2),chaxun(p[root].rs,mid+1,end,begin2,end2));
}
int getans(int x,int y){
int ans=0;
for (;x>=1;x-=(x&-x))ans=max(ans,chaxun(rt[x],1,INF,1,y));
return ans;
}
void upd(int x,int y,int z){
for (;x<=INF;x+=(x&-x))
{
if (!rt[x])rt[x]=++cnt;
gengxin(rt[x],1,INF,y,z);
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
Max[i]=Min[i]=a[i];
}
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
Max[x]=max(Max[x],y);
Min[x]=min(Min[x],y);
}
for (int i=1;i<=n;i++)
{
f[i]=getans(Min[i],a[i])+1;
upd(a[i],Max[i],f[i]);
ans=max(ans,f[i]);
}
printf("%d\n",ans);
return 0;
}