Description
Solution
先搞一个
n2
的暴力,
设原序列为
ai
,变化的最大为
Bxi
,最小为
Bii
,
枚举j转移过来,要满足在所有的变一个的情况下的不下降,那么肯定是当前的
aj⩽Bii
&
Bxj⩽ai
,
转移方程:
fi=maxaj⩽Bii,Bxj⩽ai{fj+1}
复杂度: O(n2) ;
优化:
我们发现,这个东西可以用树套树来搞,
用树状数组维护第一个,再套个4线段树维护第二个,
线段树动态开节点即可,
复杂度: O(nlog2(n)) ;
PS:大概想了一下,其实树状数组套树状数组好像也可以。
Code
#include<cstdio>
#include<cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define NX(q) ((q)&(-(q)))
using namespace std;
const int N=100050;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,m1,ans;
int a[N],f[N];
int B[N][2];
int root[N],b0=0;
struct qqww
{int l,r,s;}b[N*60];
int max(int q,int w){return q<w?w:q;}
int min(int q,int w){return q>w?w:q;}
int find(int l,int r,int e,int r1)
{
if(!e)return 0;
if(r<=r1)return b[e].s;
int t=(l+r)/2;
if(r1<=t)return find(l,t,b[e].l,r1);
else return max(find(l,t,b[e].l,r1),find(t+1,r,b[e].r,r1));
}
void change(int l,int r,int &e,int r1,int l2)
{
if(!e)e=++b0;
if(l==r){b[e].s=max(b[e].s,l2);return;}
int t=(l+r)/2;
if(r1<=t)change(l,t,b[e].l,r1,l2);
else change(t+1,r,b[e].r,r1,l2);
b[e].s=max(b[b[e].l].s,b[b[e].r].s);
}
int main()
{
int q,w,mx=0;
read(n);read(m1);
fo(i,1,n)B[i][0]=B[i][1]=read(a[i]);
fo(i,1,m1)read(q),read(w),B[q][0]=min(w,B[q][0]),B[q][1]=max(B[q][1],w);
fo(i,1,n)mx=max(mx,B[i][1]);
fo(i,1,n)
{
f[i]=1;
for(q=a[i];q;q-=NX(q))f[i]=max(f[i],find(1,mx,root[q],B[i][0])+1);
for(q=B[i][1];q<=mx;q+=NX(q))change(1,mx,root[q],a[i],f[i]);
ans=max(ans,f[i]);
}
printf("%d\n",ans);
return 0;
}