区间 LIS
我们声称区间 LIS 可以做到 \(\mathcal{O}(n \log^2 n)\)。具体见 link1 和 link2。但是这里给出的是 \(\mathcal{O}(n \sqrt{n} \log n)\) 的做法。
考虑 LIS 的求法,DP 显然很倒闭,另外一种是 \(f_i\) 表示 LIS 为 \(i\),结尾的数最小是多少,加入一个数 \(x\),则转移为 \(\forall f_i < x, f_{i + 1} \leftarrow \min(f_{i + 1}, x)\)。这就相当于,每次找到最小的 \(> x\) 的数,然后让 \(x\) 代替它的作用。
刻画一下这个过程,考虑一个初始为空的集合 \(S\),每次加入一个数 \(x\),如果 \(S\) 中没有比 \(x\) 更大的数,就让 \(S \leftarrow S \cup \{x\}\),否则将最小的 \(> x\) 的数修改为 \(x\)。则 LIS 就是最后 \(S\) 的大小。
设区间 \([l, r]\) 进行这个过程得到的集合为 \(S_{l, r}\),有如下性质:
- \(S_{l, r} \subseteq S_{l - 1, r}\)
- \(|S_{l - 1, r}| - |S_{l, r}| \le 1\)
证明是显然的,你考虑一开始令 \(S_{l, r} = \varnothing, S_{l - 1, r} = p_{l - 1}\),然后对 \([l, r]\) 进行这个过程,就发现是对的了。
那么 \(r\) 固定时,对于 \(x\),一定有一个前缀 \(l\) 满足 \(\forall i \le l, x \in S_{i, r}, \forall i > l, x \notin S_{i, r}\),记这个 \(l\) 为 \(a_x\),那么询问就是问 \(a_x \ge l\) 的 \(x\) 有多少个。考虑对 \(r\) 扫描线,\(r \rightarrow r + 1\) 时,记 \(v = p_{r + 1}\),\(a_v\) 显然会变为 \(r + 1\),且一开始有一个变量 \(x = 0\),对于 \(i = v + 1, v + 2, \dots, n\) 依次考虑,如果 \(a_i > x\) 则 \(a_i\) 和 \(x\) 交换,这就是模拟 \(S\) 中加了一个 \(v\) 后的改变。
然后发现这不是我们 P14400 吗。直接改改就过了,时间复杂度 \(\mathcal{O}(n \sqrt{n} \log n)\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// typedef __int128 i128;
typedef pair<int, int> pii;
const int N = 1e5 + 10, B = 317, mod = 998244353;
template<typename T>
void dbg(const T &t) { cout << t << endl; }
template<typename Type, typename... Types>
void dbg(const Type& arg, const Types&... args) {
cout << arg << ' ';
dbg(args...);
}
namespace Loop1st {
int n, Q, L[B], R[B], bel[N], cnt, p[N], a[N], ans[N];
priority_queue<int>q1[B];
priority_queue<int, vector<int>, greater<int>>q2[B];
struct Query {
int l, r, id;
bool operator < (const Query &A) const {
return r < A.r;
}
} q[N];
struct Fenwick {
int tr[N];
void add(int x, int v) {
while (x) tr[x] += v, x -= x & -x;
}
int ask(int x) {
int res = 0;
while (x <= n) res += tr[x], x += x & -x;
return res;
}
} BIT;
void rebuild(int id) {
auto &pq = q2[id];
if (pq.empty()) return ;
for (int i = L[id]; i <= R[id]; i++) if (a[i] > pq.top()) {
pq.push(a[i]);
a[i] = pq.top();
pq.pop();
}
priority_queue<int, vector<int>, greater<int>>().swap(pq); // <=> pq.clear() 虽然 pq 没有 clear() 函数
}
int query(int l, int r, int x) {
int bl = bel[l], br = bel[r];
if (bl == br) {
rebuild(bl);
for (int i = l; i <= r; i++) if (a[i] > x) swap(a[i], x);
priority_queue<int>(a + L[bl], a + R[bl] + 1).swap(q1[bl]); // 即令 q1[bl] = {a[L[bl]], a[L[bl] + 1], ..., a[R[bl]]}
return x;
}
rebuild(bl); rebuild(br);
for (int i = l; i <= R[bl]; i++) if (a[i] > x) swap(a[i], x);
priority_queue<int>(a + L[bl], a + R[bl] + 1).swap(q1[bl]);
for (int i = bl + 1; i < br; i++) {
if (x >= q1[i].top()) continue;
q2[i].push(x);
q1[i].push(x);
x = q1[i].top();
q1[i].pop();
}
for (int i = L[br]; i <= r; i++) if (a[i] > x) swap(a[i], x);
priority_queue<int>(a + L[br], a + R[br] + 1).swap(q1[br]);
return x;
}
void main() {
cin >> n >> Q;
cnt = (n + B - 1) / B;
for (int i = 1; i <= cnt; i++) {
L[i] = R[i - 1] + 1;
R[i] = i * B;
}
R[cnt] = n;
for (int i = 1; i <= n; i++) {
bel[i] = (i + B - 1) / B;
cin >> p[i];
q1[bel[i]].push(0);
}
for (int i = 1, l, r; i <= Q; i++) {
cin >> l >> r;
q[i] = {l, r, i};
}
sort(q + 1, q + Q + 1);
// 0 永远不会被 ask 到,所以不用 BIT 维护 0
for (int r = 1, now = 1; r <= n; r++) {
int v = p[r];
if (v < n) {
int x = query(v + 1, n, 0);
BIT.add(x, -1);
}
int b = bel[v];
rebuild(b);
BIT.add(a[v], -1); a[v] = r; BIT.add(a[v], 1);
priority_queue<int>(a + L[b], a + R[b] + 1).swap(q1[b]);
while (now <= Q && q[now].r == r) ans[q[now].id] = BIT.ask(q[now].l), now++;
}
for (int i = 1; i <= Q; i++) cout << ans[i] << '\n';
}
}
int main() {
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T = 1;
// cin >> T;
while (T--) Loop1st::main();
return 0;
}
// start coding at 10:20
// finish debugging at 10:27

浙公网安备 33010602011771号