2022杭电多校5 A Pandaemonium Asphodelos: The First Circle (Savage)

题目描述

https://acm.hdu.edu.cn/showproblem.php?pid=7185

简要题意:现在有一个长度为 $n$ 的序列,每个位置有权值 $a_i$ 和颜色 $c_i$ 两个属性,现在有 $m$ 次操作,操作有四种,第一种操作给定 $x$ 和 $c$,表示将与 $x$ 最近的 $c$ 个数(包括 $x$ 自身在内)的颜色都变成一种未出现过的颜色;第二种操作给定 $x$ 和 $y$,将与 $y$ 颜色相同且与 $y$ 相连的颜色段的颜色都变成 $x$ 所在颜色段的颜色;第三种操作给定 $x$ 和 $v$,将与 $x$ 同色的所有位置的权值都加 $v$;第四种操作给定 $x$,求 $x$ 的权值

$n\le 10^8,m\le 10^5$,强制在线

Solution

我们可以用珂朵莉树维护颜色段,因为我们所有的操作在遍历到一个颜色段后都会将其删除,所以复杂度是正确的

对于权值修改,我们直接在全集记录每种颜色的权值增量,这样我们只需要在一个位置的颜色改变的时候做区间修改即可,注意到 $n$ 很大,我们可以使用动态开点线段树或树状数组,动态开点树状数组需要 $map$ 或者手写 $hash$ 表在常数上表现不如动态开点线段树

时间复杂度 $O(m\log n)$

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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <iostream>
#include <set>
#include <algorithm>
#include <unordered_map>
#include <vector>
#define ll long long
#define maxn 100010
#define lowbit(i) ((i) & (-i))
using namespace std;

struct Hashtable {
const int p = 20011203;
struct node {
int k; ll v; int next;
} pool[10000000]; vector<int> clr; int tab[20011203], top;

void ins(int k, ll v) {
for (int i = tab[k % p]; i; i = pool[i].next) {
node &u = pool[i];
if (u.k == k) return u.v += v, void();
}
pool[++top] = { k, v, tab[k % p] };
tab[k % p] = top; clr.push_back(k % p);
}
void init() {
for (auto t : clr) tab[t] = 0;
clr.clear(); top = 0;
}
ll query(int k) {
for (int i = tab[k % p]; i; i = pool[i].next) {
node &u = pool[i];
if (u.k == k) return u.v;
} return 0;
}
} Bit;

int n, q;
ll tag[maxn];

void add(int i, ll v) { while (i <= n) Bit.ins(i, v), i += lowbit(i); }

ll get_sum(int i) {
ll s = 0;
while (i) s += Bit.query(i), i -= lowbit(i);
return s;
}

struct Chtolly {
int l, r;
mutable int v;

Chtolly(int l = 0, int r = 0, int v = 0) : l(l), r(r), v(v) {}
friend bool operator < (const Chtolly &u, const Chtolly &v) { return u.l < v.l; }
}; set<Chtolly> S;

set<Chtolly>::iterator split(int k) {
auto it = S.lower_bound(Chtolly(k));
if (it != S.end() && it -> l == k) return it;
it = prev(it); Chtolly t = *it;
if (it -> r < k) return S.end();
return S.erase(it), S.emplace(t.l, k - 1, t.v), S.emplace(k, t.r, t.v).first;
}

void assign(int l, int r, int v) {
auto itr = split(r + 1), itl = split(l);
for (auto it = itl; it != itr; ++it) {
add(it -> l, tag[it -> v]);
add(it -> r + 1, -tag[it -> v]);
}
S.erase(itl, itr);
S.emplace(l, r, v);
add(l, -tag[v]); add(r + 1, tag[v]);
}

set<Chtolly>::iterator find(int k) { return prev(S.upper_bound(Chtolly(k))); }

set<Chtolly>::iterator merge(int k) {
auto it = find(k), itl = it, itr = it;
while (itr != S.end() && itr -> v == it -> v) ++itr;
while (itl != S.begin() && prev(itl) -> v == it -> v) itl = prev(itl);
Chtolly t = Chtolly(itl -> l, prev(itr) -> r, it -> v);
return S.erase(itl, itr), S.insert(t).first;
}

int lans, cnt;
inline void solve_1() {
int x, y, l, r; cin >> x >> y;
x = (x - 1 ^ lans) % n + 1; y = (y - 1 ^ lans) % ((n - 1) / 2) + 1;
l = max(1, x - y); r = l + 2 * y;
if (r > n) l = n - 2 * y, r = n;
assign(l, r, ++cnt);
}

inline void solve_2() {
int x, y; cin >> x >> y;
x = (x - 1 ^ lans) % n + 1; y = (y - 1 ^ lans) % n + 1;
int v = find(x) -> v; auto it = merge(y);
add(it -> l, tag[it -> v] - tag[v]); add(it -> r + 1, tag[v] - tag[it -> v]);
it -> v = v;
}

inline void solve_3() {
int x, y; cin >> x >> y;
x = (x - 1 ^ lans) % n + 1;
tag[find(x) -> v] += y;
}

inline void solve_4() {
int x; ll ans = 0; cin >> x;
x = (x - 1 ^ lans) % n + 1;
cout << (ans = tag[find(x) -> v] + get_sum(x)) << "\n";
lans = ans & 1073741823;
}

void work() {
cin >> n >> q;
Bit.init(); lans = 0;
for (int i = 1; i <= cnt; ++i) tag[i] = 0; cnt = 0;
S.clear(); S.emplace(1, n, ++cnt);
for (int i = 1; i <= q; ++i) {
int opt; cin >> opt;
switch (opt) {
case 1: solve_1(); break;
case 2: solve_2(); break;
case 3: solve_3(); break;
case 4: solve_4(); break;
}
}
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

int T; cin >> T;
while (T--) work();
return 0;
}