题目大意:
一个有 n n n个数的序列,有 Q Q Q次修改,每次改变某个数的数值,求整个序列的 L I S LIS LIS,修改间互相不影响。
n , m ≤ 5 e 5 n,m≤5e5 n,m≤5e5
分析:
对于每次的操作
a
[
x
]
=
y
a[x]=y
a[x]=y,我们可以进行排序然后离线操作,
对于某次操作
a
[
x
]
=
y
a[x]=y
a[x]=y,
我们求出当
a
[
x
]
=
y
a[x]=y
a[x]=y时,
以
y
y
y结尾的
1
1
1到
x
x
x的最长严格上升子序列,设为
L
[
i
]
L[i]
L[i]
以
y
y
y开头的
x
x
x到
n
n
n的最长严格上升子序列,设为
R
[
i
]
R[i]
R[i]
然后我们求出原序列
a
a
a的
a
l
[
i
]
al[i]
al[i]跟
a
r
[
i
]
ar[i]
ar[i],设原序列的最长严格上升子序列长度为
k
k
k
我们可以发现,
当
L
[
i
]
+
R
[
i
]
−
1
>
=
k
L[i]+R[i]-1 >= k
L[i]+R[i]−1>=k时,就代表了修改后的位置
a
[
x
]
a[x]
a[x]对于答案有影响的,而此时的最长严格上升子序列长度则为
L
[
i
]
+
R
[
i
]
−
1
L[i]+R[i]-1
L[i]+R[i]−1
当
a
l
[
i
]
+
a
r
[
i
]
−
1
=
k
al[i]+ar[i]-1=k
al[i]+ar[i]−1=k时,
我们可以发现,如果
a
[
x
]
a[x]
a[x]存在于原序列的
L
I
S
LIS
LIS中的第
c
c
c位,那么对于原序列的多个
L
I
S
LIS
LIS,它都是在第
c
c
c位的,那么我们只需要判断第
c
c
c位置的选择数目即可,如果不为1,那么就代表存在相等作用的数能够代替它发挥作用,此时我们的答案就是
k
k
k,否则就是
k
−
1
k-1
k−1
求的过程经过某博客指点发现可以用离散xjb乱求
代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#define inf 0x3f3f3f3f
#define N 500005
using namespace std;
struct Node { int x, y, id, lnum, rnum; }C[N];
int Answer[N], Check[N], lisl[N], lisr[N], a[N], f[N], len, cnt, n, m;
void read(int &x)
{
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if ( s == '-') f = -1; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
x = x * f;
}
void write(int x)
{
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
bool cmp(Node aa, Node bb)
{
return aa.x < bb.x;
}
int main()
{
freopen("kite.in", "r", stdin);
freopen("kite.out", "w", stdout);
read(n); read(m);
for (int i = 1; i <= n; i++) read(a[i]);
for (int i = 1; i <= m; i++) read(C[i].x), read(C[i].y), C[i].id = i;
sort(C + 1, C + m + 1, cmp);
len = 0; cnt = 1;
for (int i = 1; i <= n; i++) f[i] = inf;
for (int i = 1; i <= n; i++)
{
while (cnt <= m && C[cnt].x == i)
{
int pos = lower_bound(f + 1, f + n + 1, C[cnt].y) - f;
C[cnt++].lnum = pos;
}
int pos = lower_bound(f + 1, f + n + 1, a[i]) - f;
lisl[i] = pos; f[pos] = a[i]; len = max(len, pos);
}
cnt = m;
for (int i = 1; i <= n; i++) f[i] = inf;
for (int i = n; i >= 1; i--)
{
while (cnt >= 1 && C[cnt].x == i)
{
int pos = lower_bound(f + 1, f + n + 1, -C[cnt].y) - f;
C[cnt--].rnum = pos;
}
int pos = lower_bound(f + 1, f + n + 1, -a[i]) - f;
lisr[i] = pos; f[pos] = -a[i];
}
for (int i = 1; i <= n; i++)
if (lisl[i] + lisr[i] > len) Check[lisl[i]]++;
for (int i = 1; i <= m; i++)
if (C[i].lnum + C[i].rnum > len) Answer[C[i].id] = C[i].lnum + C[i].rnum - 1;
else if (lisl[C[i].x] + lisr[C[i].x] > len && Check[lisl[C[i].x]] == 1) Answer[C[i].id] = len - 1;
else Answer[C[i].id] = len;
for (int i = 1; i <= m; i++) write(Answer[i]), printf("\n");
return 0;
}