0%

2024 Nowcoder Round 4 Tutorial

123

L

场上想的还是不太好实现,绕不开要处理大数。

对时间区间维护 \((k,s,r)\) 表示该区间中有 \(k\) 个减速,至少需要 \(s\) 的时间才能通过这段区间,以 \(s\) 的时间通过这段区间后,还会剩下 \(r\) 的时间。

这题先离散化坐标,后对于每一个初始位置的初始状态为 \((t,p_{nxt}-p_{now}+1,,2^t)\),合并也是可以合并的,然后就做完了。

这题比较烦人的是要维护是否取模,还要支持减法,有些corner case就很恶心。不过实际上可以直接维护那个数的真实值,涉及比较的直接拿真实值比就好,细节见代码。

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
139
140
141
142
143
144
145
#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using i128 = __int128_t;

constexpr int P = 1e9 + 7, N = 500100;
constexpr i64 inf = 1e18;

struct Z {
int a; i64 true_val;
Z() : a(0), true_val(0) {}
Z(int a) : a(a), true_val(a) {}
Z operator+(const Z &b) const {
Z res;
res.a = a + b.a;
if(res.a >= P) res.a -= P;
res.true_val = min(inf, true_val + b.true_val);
return res;
}
Z operator+(const int b) const {
Z res = *this + Z(b);
return res;
}
Z operator-(const int b) const {
Z res;
assert(true_val >= b);
res.a = (a - b + P) % P;
res.true_val = true_val - b;
return res;
}
Z operator*(const Z &b) const {
Z res;
res.a = 1ll * a * b.a % P;
res.true_val = min((i128)inf, (i128)true_val * b.true_val);
return res;
}
Z operator*(const int b) const {
Z res = *this * Z(b);
return res;
}
};

int pos[N], tot; Z pw2[N];
struct node {
int k, s; Z r;
} seg[N * 4];
ostream& operator<<(ostream &os, const node &a) {
return os << a.k << ' ' << a.s << ' ' << a.r.a << ' ' << a.r.true_val;
}
node operator+(const node &a, const node &b) {
node res;
auto [k1, s1, r1] = a;
auto [k2, s2, r2] = b;
res.k = k1 + k2;
if(s2 > r1.true_val) {
int need = (s2 - r1.true_val + pw2[k1].true_val - 1) / pw2[k1].true_val;
res.s = s1 + need;
res.r = ((r1 + pw2[k1] * need) - s2) * pw2[k2] + r2;
} else {
res.s = s1;
res.r = (r1 - s2) * pw2[k2] + r2;
}
return res;
}
void build(int k, int l, int r) {
if(r == l + 1) {
seg[k] = {0, pos[r] - pos[l] + 1, Z(1)};
return;
}
int m = l + r >> 1;
build(k << 1, l, m);
build(k << 1 | 1, m, r);
seg[k] = seg[k << 1] + seg[k << 1 | 1];
}
void modify(int k, int l, int r, int p) {
if(r == l + 1) {
seg[k].k++;
seg[k].r = seg[k].r + seg[k].r;
return;
}
int m = l + r >> 1;
if(p < m) modify(k << 1, l, m, p);
else modify(k << 1 | 1, m, r, p);
seg[k] = seg[k << 1] + seg[k << 1 | 1];
}
int query(int k, int l, int r, i64 lst) {
if(r == l + 1) return pos[l] + lst;
int m = l + r >> 1;
auto left = seg[k << 1];
if(lst < left.s) return query(k << 1, l, m, lst);
else return query(k << 1 | 1, m, r, left.r.a + (lst - left.s) * pw2[left.k].a);
}
void print(int k, int l, int r) {
cerr << l << ' ' << r << ": " << seg[k] << '\n';
if(r == l + 1) return;
int m = l + r >> 1;
print(k << 1, l, m);
print(k << 1 | 1, m, r);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
pw2[0] = 1;
for(int i = 1; i < N; i++) {
pw2[i] = pw2[i - 1] + pw2[i - 1];
}
int q;
cin >> q;
vector<array<int, 2>> que(q + 1);
for(int i = 1; i <= q; i++) {
cin >> que[i][0] >> que[i][1];
if(que[i][0] == 1) {
pos[++tot] = que[i][1];
}
}
sort(pos + 1, pos + 1 + tot);
tot = unique(pos + 1, pos + 1 + tot) - pos - 1;
if(tot == 0) {
for(int i = 1; i <= q; i++) {
cout << que[i][1] << '\n';
}
return 0;
}
for(int i = 1; i <= q; i++) {
if(que[i][0] == 1) {
que[i][1] = lower_bound(pos + 1, pos + 1 + tot, que[i][1]) - pos;
}
}
build(1, 0, tot);
for(int i = 1; i <= q; i++) {
if(que[i][0] == 1) {
modify(1, 0, tot, que[i][1] - 1);
} else {
int x = que[i][1];
if(x >= seg[1].s) {
cout << (seg[1].r + pos[tot] + pw2[seg[1].k] * (x - seg[1].s)).a << '\n';
} else {
cout << query(1, 0, tot, x) << '\n';
}
}
}
cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
return 0;
}