-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathabc217_d.py
More file actions
269 lines (241 loc) · 7.3 KB
/
Copy pathabc217_d.py
File metadata and controls
269 lines (241 loc) · 7.3 KB
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
###############################################
[cgpt AC explanation]
このコードは**Treap**(Tree + Heap)と呼ばれる平衡二分探索木を使用して、木材の切断とクエリ処理を行うプログラムです。以下に詳細な説明をします。
## 全体の概要
- 長さLの木材があり、Q個のクエリを処理します
- クエリタイプ1: 位置xで木材を切断
- クエリタイプ2: 位置xを含む木材片の長さを出力
## データ構造: Treap
```python
class TreapNode:
__slots__ = ("key", "priority", "left", "right")
def __init__(self, key):
self.key = key # 切断位置の座標
self.priority = random.random() # 優先度(ランダム)
self.left = None # 左子ノード
self.right = None # 右子ノード
```
- **二分探索木の性質**: 左子孫 < 親 < 右子孫
- **ヒープの性質**: 親の優先度 > 子の優先度
- これにより平衡が保たれ、効率的な操作が可能
## 主要関数の説明
### 1. `split(root, key)`
```python
def split(root, key):
if not root:
return (None, None)
if key < root.key:
l, root.left = split(root.left, key)
return (l, root)
else:
root.right, r = split(root.right, key)
return (root, r)
```
- 木をkeyを境に2つに分割
- keyより小さい部分と大きい部分に分ける
### 2. `merge(a, b)`
```python
def merge(a, b):
if not a or not b:
return a or b
if a.priority > b.priority:
a.right = merge(a.right, b)
return a
else:
b.left = merge(a, b.left)
return b
```
- 2つの木をマージ
- 優先度に基づいて再帰的に結合
### 3. `insert(root, node)`
```python
def insert(root, node):
if not root:
return node
if node.priority > root.priority:
l, r = split(root, node.key)
node.left, node.right = l, r
return node
elif node.key < root.key:
root.left = insert(root.left, node)
else:
root.right = insert(root.right, node)
return root
```
- 新しい切断位置を挿入
- 優先度が高い場合は分割して挿入
- 優先度が低い場合は通常のBST挿入
### 4. `lower_bound(root, key)`
```python
def lower_bound(root, key):
res = None
while root:
if root.key >= key:
res = root
root = root.left
else:
root = root.right
return res
```
- key以上の最小の切断位置を検索
- xを含む木材片の右端を求める
### 5. `prev_bound(root, key)`
```python
def prev_bound(root, key):
res = None
while root:
if root.key < key:
res = root
root = root.right
else:
root = root.left
return res
```
- key未満の最大の切断位置を検索
- xを含む木材片の左端を求める
## メイン処理の流れ
### 初期化
```python
L, Q = map(int, input().split())
root = TreapNode(0) # 開始点(0)を挿入
root = insert(root, TreapNode(L)) # 終了点(L)を挿入
```
- 木材は最初 [0, L] の1区間
### クエリ処理
```python
for _ in range(Q):
c, x = map(int, input().split())
if c == 1:
root = insert(root, TreapNode(x)) # 切断位置を追加
else:
r = lower_bound(root, x) # x以上の最小切断点
l = prev_bound(root, x) # x未満の最大切断点
print(r.key - l.key) # 木材片の長さを出力
```
## 具体例で見る動作
**例**: L=10, クエリ: (1,3), (1,7), (2,5)
1. 初期状態: 切断点 [0, 10] → 長さ10の木材1本
2. (1,3)で切断: 切断点 [0, 3, 10] → 木材 [0-3], [3-10]
3. (1,7)で切断: 切断点 [0, 3, 7, 10] → 木材 [0-3], [3-7], [7-10]
4. (2,5)のクエリ:
- lower_bound(5) = 7 (5以上の最小切断点)
- prev_bound(5) = 3 (5未満の最大切断点)
- 結果: 7 - 3 = 4
## 特徴と利点
1. **効率性**: 各操作が平均O(log N)時間
2. **動的更新**: 切断点の追加を効率的に処理
3. **範囲検索**: 前後の切断点を高速に検索可能
このTreapデータ構造により、大量のクエリを高速に処理できます。
###############################################
[cgpt AC]
import sys, random
input = sys.stdin.readline
class TreapNode:
__slots__ = ("key", "priority", "left", "right")
def __init__(self, key):
self.key = key
self.priority = random.random()
self.left = None
self.right = None
def split(root, key):
if not root:
return (None, None)
if key < root.key:
l, root.left = split(root.left, key)
return (l, root)
else:
root.right, r = split(root.right, key)
return (root, r)
def merge(a, b):
if not a or not b:
return a or b
if a.priority > b.priority:
a.right = merge(a.right, b)
return a
else:
b.left = merge(a, b.left)
return b
def insert(root, node):
if not root:
return node
if node.priority > root.priority:
l, r = split(root, node.key)
node.left, node.right = l, r
return node
elif node.key < root.key:
root.left = insert(root.left, node)
else:
root.right = insert(root.right, node)
return root
def lower_bound(root, key):
res = None
while root:
if root.key >= key:
res = root
root = root.left
else:
root = root.right
return res
def prev_bound(root, key):
res = None
while root:
if root.key < key:
res = root
root = root.right
else:
root = root.left
return res
L, Q = map(int, input().split())
root = TreapNode(0)
root = insert(root, TreapNode(L))
for _ in range(Q):
c, x = map(int, input().split())
if c == 1:
root = insert(root, TreapNode(x))
else:
r = lower_bound(root, x)
l = prev_bound(root, x)
print(r.key - l.key)
###############################################
[cgpt TLE]
import sys
import bisect
L, Q = map(int, sys.stdin.readline().split())
C = [0, L]
for _ in range(Q):
c, x = map(int, sys.stdin.readline().split())
if c == 1:
i = bisect.bisect(C, x)
C.insert(i, x) # O(N) 挿入
else:
i = bisect.bisect(C, x)
print(C[i] - C[i-1])
###############################################
[my TLE]
L,Q=map(int,input().split())
C=[0,L]
from bisect import bisect_left,bisect_right,bisect
for i in range(Q):
c,x=map(int,input().split())
if c==1:
C+=[x]
C.sort()
elif c==2:
j=bisect(C,x)
print(C[j]-C[j-1])
###############################################