题目描述:
雾。
题目分析:
先来分析一下50分的DP.
DP[i]表示以i结尾可选出的最长原序列.
DP[i]=max(DP[j])+1(maxv[j]<=val[i]&&val[j]<=minv[i],j < i)
其中 maxv为能够变化到的最大值,minv为能够变化到的最小值,val为原值
上面的DP方程显然。
这样转移为
N2
N
2
可以过掉50的数据
考虑优化转移,我们需要快速得到 符合条件的 MAX_DP[j]
转为二维平面 我们 只需要把一个看为横坐标,一个看出纵坐标,然后在坐下的矩形中查找最大的值就OK了。
如何实现这个矩形查找?
二维平面需要靠树套树
一维 维护x,一维 维护y
线段树套线段树即可,需要动态开点维护.
然而内存还是大的一批,最后用了BIT套线段树
转移为
N(logN)2
N
(
l
o
g
N
)
2
题目链接:
AC 代码:
不封装用的变量冲突太多TAT
#include <cstdio>
#include <iostream>
#define il inline
#define lowbit(x) x&-x
const int maxm=1e5+100;
int maxv[maxm],minv[maxm],val[maxm],n,k;
int dp[maxm];
int MaxA,MaxV;
il int read()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9')
{
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
struct T{
struct node{
int ls,rs,maxx;
};
node st[maxm<<6];
int rt;
int askmax(int &now,int l,int r,int ql,int qr)
{
if(!now) return -1;
if(r<ql||l>qr) return -1;
if(ql<=l&&r<=qr)
return st[now].maxx;
int mid=(l+r)>>1;
return std::max(askmax(st[now].ls,l,mid,ql,qr),askmax(st[now].rs,mid+1,r,ql,qr));
}
void insert(int &now,int l,int r,int ind,int num)
{
if(!now) now=++rt;
if(l>=r)
{
st[now].maxx=num;
return;
}
int mid=(l+r)>>1;
if(ind<=mid) insert(st[now].ls,l,mid,ind,num);
else insert(st[now].rs,mid+1,r,ind,num);
st[now].maxx=std::max(st[st[now].ls].maxx,st[st[now].rs].maxx);
}
}tree;
struct B{
int root[maxm];
void insert(int x,int y,int v)
{
for(int i=x;i<=MaxV;i+=lowbit(i))
tree.insert(root[i],1,MaxA,y,v);
}
int askans(int x,int y)
{
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans=std::max(ans,tree.askmax(root[i],1,MaxA,1,y));
return ans;
}
}BIT;
int main()
{
n=read(),k=read();
for(int i=1;i<=n;i++) val[i]=maxv[i]=minv[i]=read(),MaxA=std::max(MaxA,val[i]);
for(int i=1,x,y;i<=k;i++)
{
x=read(),y=read();
maxv[x]=std::max(maxv[x],y);
minv[x]=std::min(minv[x],y);
MaxV=std::max(MaxV,maxv[i]);
}
int ans=0;
for(int i=1;i<=n;i++)
{
int v=BIT.askans(minv[i],val[i])+1;
BIT.insert(val[i],maxv[i],v);
ans=std::max(ans,v);
}
printf("%d\n",ans);
return 0;
}