bzoj 4553 序列

$cdq$ 分治处理三维偏序.

  • 记位置 $i$ 原本的值为 $a_i$ ,可能出现的最大值为 $mx_i$ ,可能出现的最小值为 $mn_i$ .像普通的 $LIS$ 那样,设 $f(i)$ 表示必须以第 $i$ 个数结尾的 $LIS$ 长度.
  • 因为每次只能有一个位置被修改,不难发现完成转移 $f(i)\leftarrow f(j)+1$ 需要同时满足三个条件, $mx_j\leq a_i,a_j\leq mn_i,j<i​$ .
  • 就是一个三维偏序,贡献又是可结合的,于是用 $cdq$ 分治处理即可.时间复杂度 $O(n\cdot log^2n)$ .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int MAXN=1e5+10;
int n,m,a[MAXN],mx[MAXN],mn[MAXN];
int f[MAXN];
struct FenwickTree
{
int bit[MAXN];
FenwickTree(){memset(bit,0,sizeof bit);}
#define lowbit(x) x&(-x)
void add(int x,int c)
{
for(;x<=n;x+=lowbit(x))
bit[x]=max(bit[x],c);
}
void rst(int x)
{
for(;x<=n;x+=lowbit(x))
bit[x]=0;
}
int sum(int x)
{
int s=0;
for(;x;x-=lowbit(x))
s=max(s,bit[x]);
return s;
}
}T;
struct opt
{
int x,y,pos;
bool operator < (const opt &rhs) const
{
return y==rhs.y?pos<=rhs.pos:y<=rhs.y;
}
}q[MAXN];
void cdq(int L,int R)
{
if(L==R)
return;
int mid=(L+R)>>1;
cdq(L,mid);
int tot=0;
for(int i=L;i<=R;++i)
{
q[++tot].pos=i;
if(i<=mid)
q[tot].x=mx[i],q[tot].y=a[i];
else
q[tot].x=a[i],q[tot].y=mn[i];
}
sort(q+1,q+1+tot);
for(int i=1;i<=tot;++i)
{
if(q[i].pos<=mid)
T.add(q[i].x,f[q[i].pos]);
else
f[q[i].pos]=max(f[q[i].pos],T.sum(q[i].x)+1);
}
for(int i=1;i<=tot;++i)
if(q[i].pos<=mid)
T.rst(q[i].x);
cdq(mid+1,R);
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;++i)
{
mx[i]=mn[i]=a[i]=read();
f[i]=1;
}
for(int i=1;i<=m;++i)
{
int pos=read(),x=read();
mx[pos]=max(mx[pos],x);
mn[pos]=min(mn[pos],x);
}
cdq(1,n);
cout<<f[n]<<endl;
return 0;
}