「计蒜客模拟赛」自适应平衡多叉处理数据结构

#T3244. 「计蒜客模拟赛」自适应平衡多叉处理数据结构

Summarize

维护数据结构,每次询问时执行 $O(\sqrt n)$ 次查询操作,每次修改执行一次修改操作。

$n\le 300000$

Solution

50pts

观察到每次前移 $i$ 步时,下一步停止或前移 $i+1$ 步。因此前移次数不超过 $\sqrt t$ 次。

维护树状数组,$O(\log n)$ 修改,$O(\log n)$ 查询。时间复杂度 $O(n\log n\sqrt n)$。

100pts

使用 根号平衡 优化数据结构,$O(\sqrt n)$ 修改,$O(1)$ 查询。时间复杂度 $O(n\sqrt n)$

Note

使用分块思想处理修改-查询操作序列

  • 均摊复杂度

    参考 「计蒜客 2020.2 提高组」保卫水库

    适用条件:修改操作具有可累加性

    对于查询操作,将其之前的所有修改操作单独处理均需 $O(1)$ 复杂度;也可将所有修改操作全局标记,需要 $O(n)$ 复杂度。

    考虑维护一个修改操作集合。查询操作将操作集合中的所有修改操作单独处理。当操作集合大小达到 $\sqrt n$ 时,进行一次全局标记并清空集合。

    均摊时间复杂度 $O(n\sqrt n)$。

  • 根号平衡

    通过降低修改复杂度、提高查询复杂度,或降低查询复杂度、提高修改复杂度,以达到平衡,取得最优全局复杂度。

Code

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
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 3e5 + 5;

int t, q, l; //tql

int c[MAXN], d[MAXN];
// s[i] = c[i] + d[i / l]

inline void modify(int p) {
int t1 = (p / l + 1) * l - 1;
t1 = min(t1, t);
for (int i = p; i <= t1; ++i)
c[i]++;
int t2 = t / l;
for (int i = p / l + 1; i <= t2; ++i)
d[i]++;
}

inline int query(int p) {
return c[p] + d[p / l];
}

int main() {
freopen("task.in", "r", stdin);
freopen("task.out", "w", stdout);
scanf("%d%d", &t, &q);
l = sqrt(t);
while (q--) {
int tp, cur;
scanf("%d%d", &tp, &cur);
if (tp == 0) {
modify(cur);
} else {
int stp = 0, lst = 0;
while (1) {
int t1 = query(cur), t2 = query(lst);
stp = t1 - t2;
if (!stp) break;
lst = cur, cur += t1;
if (cur > t) {
cur = -1;
break;
}
}
printf("%d\n", cur);
}
}
return 0;
}
# 分块

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×