-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathidea_live_templates.xml
315 lines (315 loc) · 137 KB
/
idea_live_templates.xml
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
<template name="combinatorics.bellnumber" value="/** * Computes Bell triangle. * ret[n][n] := Bell number of x. * ret[n][k] := The number of partitions of the set {1,2,...,n+1} s.t. k+1 is the largest singleton of the partition. * * O(n^2) * * @refs https://en.wikipedia.org/wiki/Bell_triangle#Combinatorial_interpretation * @param n * @param mod * @return */ public static long[][] bellTriangle(int n, int mod) { long[][] ret = new long[n+1][n+1]; ret[0][0] = 1; for (int i = 1; i <= n ; i++) { ret[i][1] = ret[i-1][i-1]; for (int j = 2 ; j <= i ; j++) { ret[i][j] = (ret[i-1][j-1] + ret[i][j-1]) % mod; } } for (int i = 1 ; i <= n ; i++) { ret[i][0] = (ret[i][1] - ret[i-1][0] + mod) % mod; } return ret; }" description="ベル数の三角形" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="combinatorics.combination" value="static final int MOD = 1000000007; static long pow(long a, long x) { long res = 1; while (x > 0) { if (x % 2 != 0) { res = (res * a) % MOD; } a = (a * a) % MOD; x /= 2; } return res; } static long inv(long a) { return pow(a, MOD - 2) % MOD; } static long[] _fact; static long[] _invfact; static long comb(long ln, long lr) { int n = (int)ln; int r = (int)lr; if (n < 0 || r < 0 || r > n) { return 0; } if (r > n / 2) { r = n - r; } return (((_fact[n] * _invfact[n - r]) % MOD) * _invfact[r]) % MOD; } static void prec(int n) { _fact = new long[n + 1]; _invfact = new long[n + 1]; _fact[0] = 1; _invfact[0] = 1; for (int i = 1; i <= n; i++) { _fact[i] = _fact[i - 1] * i % MOD; _invfact[i] = inv(_fact[i]); } } " toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="combinatorics.permutation" value="/** * Computes smallest lexicographically larger permutation of given array. * Modifies given array directly. * If there is no such permutation, returns false. * * @param a * @return * */ public static boolean next_permutation(int[] a) { int len = a.length; int x = len - 2; while (x >= 0 && a[x] >= a[x+1]) { x--; } if (x == -1) { return false; } int y = len - 1; while (y > x && a[y] <= a[x]) { y--; } int tmp = a[x]; a[x] = a[y]; a[y] = tmp; Arrays.sort(a, x+1, len); return true; } " description="順列の列挙" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="combinatorics.stirlingnumber" value="/** * Computes Stirling number of 1st kind up to n. * ret[n][k] means number of ways to split n labeled items into k alternating-sequences. * * @param n * @param mod * @return * */ public static long[][] stirlingFirst(int n, long mod) { long[][] ret = new long[n+1][n+1]; ret[0][0] = 1; for (int i = 1 ; i <= n ; i++) { for (int j = 1 ; j <= i ; j++) { ret[i][j] += ret[i-1][j-1]; ret[i][j] += ret[i-1][j] * (i-1); ret[i][j] %= mod; } } return ret; } /** * Computes Stirling number of 2nd kind up to n. * ret[n][k] means number of ways to split n labeled items into k non-empty groups. * * @param n * @param mod * @return * */ public static long[][] stirlingSecond(int n, long mod) { long[][] ret = new long[n+1][n+1]; ret[0][0] = 1; for (int i = 1 ; i <= n ; i++) { for (int j = 1 ; j <= i ; j++) { ret[i][j] += ret[i-1][j-1]; ret[i][j] += ret[i-1][j] * j; ret[i][j] %= mod; } } return ret; } " description="スターリング数(第一種,第二種)" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="combinatorics.subset" value="/** * Iterate subsets of X. * * @param X * @param dp */ public static void subset(int X, int[] dp) { for (int sub = (X - 1) & X ; sub > 0 ; sub = (sub - 1) & X) { dp[X] = Math.max(dp[X], dp[sub] + dp[X^sub]); } } " description="部分集合の列挙" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="count_distinct_value_in_array" value="static class Event implements Comparable<Event> { int fr; int to; int val; // plus: array value, 0 or minus: -(query index) Event(int f, int t, int ty) { fr = f; to = t; val = ty; } @Override public int compareTo(Event o) { if (fr != o.fr) { return o.fr - fr; } return o.val - val; } } static int[] countDistinctValues(int[] arr, int[][] query) { int q = query.length; int n = arr.length; BIT bit = new BIT(n+5); Event[] events = new Event[q+n]; for (int i = 0; i < q ; i++) { events[i] = new Event(query[i][0], query[i][1], -i); } for (int i = 0; i < n ; i++) { events[q+i] = new Event(i, i, arr[i]+1); } Arrays.sort(events); int[] ret = new int[q]; int max = 0; for (int i = 0; i < arr.length ; i++) { max = Math.max(max, arr[i]); } int[] lastFound = new int[max+10]; for (Event e : events) { if (e.val <= 0) { int qidx = -e.val; ret[qidx] = (int)bit.range(e.fr+1, e.to+1); } else { if (lastFound[e.val] != 0) { bit.add(lastFound[e.val], -1); } bit.add(e.fr+1, 1); lastFound[e.val] = e.fr+1; } } return ret; }" description="配列中、指定範囲に数が何種類存在するか調べる" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="dp.limited_knapsack" value="/** * Item-answerCountQuery-limited knapsack. * O(nW) * * @param dp dp value * @param item array of item({value, weight, limit}) * @param maxW quota of the knapsack */ static void itemLimitedKnapsack(int[] dp, int[][] item, int maxW) { int[] deqIdx = new int[maxW+1]; int[] deqVal = new int[maxW+1]; int n = item.length; for (int i = 0; i < n ; i++) { int v = item[i][0]; // value int w = item[i][1]; // weight int m = item[i][2]; // limit for (int a = 0 ; a < w ; a++) { int s = 0; int t = 0; for (int j = 0; j * w + a <= maxW ; j++) { int val = dp[j * w + a] - j * v; while (s < t && deqVal[t-1] <= val) { t--; } deqIdx[t] = j; deqVal[t] = val; t++; dp[j * w + a] = Math.max(dp[j * w + a], deqVal[s] + j * v); if (deqIdx[s] == j - m) { s++; } } } } } " description="個数制限ナップサック" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="dp.lis" value="/** * Computes longest increasing sequence. * If you want to get actual sequence, see dp[1..ans]. * * O(nlogn) * * @param values * @return */ public static int lis(int[] values) { int n = values.length; long[] lval = new long[n]; for (int i = 0; i < values.length; i++) { lval[i] = values[i]*1000000000L+i; } int ans = 0; long[] dp = new long[n+1]; Arrays.fill(dp, Long.MIN_VALUE); for (int i = 0; i < n; i++) { int idx = Arrays.binarySearch(dp, 0, ans+1, lval[i]); if (idx < 0) { idx = -idx-2; dp[idx+1] = lval[i]; if (idx >= ans) { ans++; } } } return ans; } " description="Longest Increasing Sequence" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.fenwick_tree" value="public class FenwickTree { long N; long[] data; public FenwickTree(int n) { N = n; data = new long[n+1]; } /** * Computes value of [1, i]. * * O(logn) * * @param i * @return */ public long sum(int i) { long s = 0; while (i > 0) { s += data[i]; i -= i & (-i); } return s; } /** * Computes value of [i, j]. * * O(logn) * * @param i * @param j * @return */ public long range(int i, int j) { return sum(j) - sum(i-1); } /** * Sets value x into i-th position. * * O(logn) * * @param i * @param x */ public void set(int i, long x) { add(i, x-range(i, i)); } /** * Adds value x into i-th position. * * O(logn) * * @param i * @param x */ public void add(int i, long x) { while (i <= N) { data[i] += x; i += i & (-i); } } }" description="Fenwick Tree (also known as BIT)" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.heap.minheap" value="import java.util.Arrays; public class MinHeap { private static final long INF = Long.MAX_VALUE; int pos; long[] data; public MinHeap(int capacity) { data = new long[capacity]; pos = 1; Arrays.fill(data, INF); } public void push(long x) { int p = pos; data[pos++] = x; while (p != 1) { int pp = p>>>1; if (data[pp] <= data[p]) { break; } long tmp = data[pp]; data[pp] = data[p]; data[p] = tmp; p = pp; } } public long peek() { return data[1]; } public long poll() { if (size() == 0) { throw new RuntimeException("queue is empty"); } pos--; long ret = data[1]; data[1] = data[pos]; data[pos] = INF; for (int p = 1 ; p * 2 < pos ; ){ int l = p<<1; int r = l+1; int to = data[l] < data[r] ? l : r; if (data[to] < data[p]) { long tmp = data[to]; data[to] = data[p]; data[p] = tmp; p = to; } else { break; } } return ret; } public int size() { return pos-1; } }" description="最小値ヒープ" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.heap.skewheapint" value="/** * Meldable heap. */ public class SkewHeapInt { static class Node { Node l, r; int value; public Node(int v) { value = v; } } Node root; int size; public int size() { return size; } public boolean isEmpty() { return root == null; } public void push(int v) { size++; root = meld(root, new Node(v)); } public int peek() { return root.value; } public int pop() { size--; int ret = peek(); root = meld(root.r, root.l); return ret; } public void clear() { root = null; size = 0; } public SkewHeapInt meld(SkewHeapInt other) { return meld(this, other); } public static SkewHeapInt meld(SkewHeapInt a, SkewHeapInt b) { Node newRoot = meld(a.root, b.root); SkewHeapInt newHeap = new SkewHeapInt(); newHeap.root = newRoot; newHeap.size = a.size + b.size; return newHeap; } public static Node meld(Node a, Node b) { if (a == null) { return b; } if (b == null) { return a; } if (a.value > b.value) { Node tmp = a; a = b; b = tmp; } a.r = meld(a.r, b); Node tmp = a.l; a.l = a.r; a.r = tmp; return a; } } " description="Implementation of meldable heap" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.heap.treapfindint" value="import utils.rand.XorShift; /** * Treap(tree+heap) */ public class TreapFindInt { private static final int INF = 100000001; static XorShift rand = new XorShift(); static class Node { Node l, r; int value; int count; int heapValue; public Node(int v) { value = v; heapValue = rand.next(); count = 1; } } Node root; public static Node update(Node a) { if (a == null) { return null; } a.count = 1 + count(a.l) + count(a.r); return a; } public static int count(Node a) { return (a == null) ? 0 : a.count; } /** * Finds node position that value = v. * If there is no such node, returns minus value. * * @param v * @return found node. */ public static int detect(Node x, int v) { if (x == null) { return -INF; } if (x.value == v) { return count(x.l); } else if (v < x.value) { return detect(x.l, v); } else { return count(x.l) + 1 + detect(x.r, v); } } /** * Merges two trees. * * @param a * @param b * @return merged root node */ public static Node merge(Node a, Node b) { if (a == null || b == null) { return a == null ? b : a; } if (a.heapValue < b.heapValue) { a.r = merge(a.r, b); return update(a); } else { b.l = merge(a, b.l); return update(b); } } /** * Splits tree at point k. [0, k), [k, n) * * @param a * @param k * @return */ public static Node[] split(Node a, int k) { if (a == null) { return new Node[]{null, null}; } if (k <= count(a.l)) { Node[] s = split(a.l, k); a.l = s[1]; return new Node[]{s[0], update(a)}; } else { Node[] s = split(a.r, k - count(a.l) - 1); a.r = s[0]; return new Node[]{update(a), s[1]}; } } /** * Inserts node v at point k. * * @param a * @param k * @return new tree */ public static Node insert(Node a, int k, Node v) { Node[] x = split(a, k); return merge(x[0], merge(v, x[1])); } /** * Erases node at point k. * * @param a * @param k * @return new tree */ public static Node erase(Node a, int k) { Node[] al = split(a, k); Node[] ar = split(al[1], 1); return merge(al[0], ar[1]); } /** * Returns size of the tree. * * @return size of the tree */ public int size() { return count(root); } /** * Adds new node to tree. * * @param v */ public void push(int v) { root = insert(root, INF, new Node(v)); } /** * Finds node position that value = v. * If there is no such node, returns minus value. * * @param v * @return */ public int detect(int v) { return detect(root, v); } /** * Removes a node value = v from tree. * * @param v */ public void remove(int v) { int pos = detect(v); if (pos >= 0) { root = erase(root, pos); } } } " description="値の検索をするTreap" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.heap.treapint" value="import utils.rand.XorShift; /** * Treap(tree+heap) */ public class TreapInt { private static final int INF = 100000001; static XorShift rand = new XorShift(); static class Node { Node l, r; int value; int count; int heapValue; public Node(int v) { value = v; heapValue = rand.next(); count = 1; } } Node root; public static Node update(Node a) { if (a == null) { return null; } a.count = 1 + count(a.l) + count(a.r); return a; } public static int count(Node a) { return (a == null) ? 0 : a.count; } /** * Grabs k-th node from given node. * * @param a * @param k * @return */ public static Node grab(Node a, int k) { if (a == null) { return null; } update(a); int l = count(a.l); if (k == l) { return a; } else if (k < l) { return grab(a.l, k); } else { return grab(a.r, k-l-1); } } /** * Merges two trees. * * @param a * @param b * @return merged root node */ public static Node merge(Node a, Node b) { if (a == null || b == null) { return a == null ? b : a; } if (a.heapValue < b.heapValue) { a.r = merge(a.r, b); return update(a); } else { b.l = merge(a, b.l); return update(b); } } /** * Splits tree at point k. [0, k), [k, n) * * @param a * @param k * @return */ public static Node[] split(Node a, int k) { if (a == null) { return new Node[]{null, null}; } if (k <= count(a.l)) { Node[] s = split(a.l, k); a.l = s[1]; return new Node[]{s[0], update(a)}; } else { Node[] s = split(a.r, k - count(a.l) - 1); a.r = s[0]; return new Node[]{update(a), s[1]}; } } /** * Inserts node v at point k. * * @param a * @param k * @return new tree */ public static Node insert(Node a, int k, Node v) { Node[] x = split(a, k); return merge(x[0], merge(v, x[1])); } /** * Erases node at point k. * * @param a * @param k * @return new tree */ public static Node erase(Node a, int k) { Node[] al = split(a, k); Node[] ar = split(al[1], 1); return merge(al[0], ar[1]); } /** * Returns size of the tree. * * @return size of the tree */ public int size() { return count(root); } /** * Adds new node value=v to the end of tree. * * @param v */ public void push(int v) { root = insert(root, INF, new Node(v)); } /** * Adds new node value=v to tree at k-th position. * * @param v */ public void push(int v, int k) { root = insert(root, k, new Node(v)); } /** * Removes k-th node from tree. * * @param k */ public void remove(int k) { root = erase(root, k); } /** * Get k-th node value * * @param k * @return */ public int get(int k) { Node n = grab(root, k); if (n == null) { return -INF; } return n.value; } } " description="場所を指定して値を挿入・削除できるTreap" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.heap.treapintrev" value="import utils.rand.XorShift; /** * Treap(tree+heap). Reversable. */ public class TreapIntRev { private static final int INF = 100000001; static XorShift rand = new XorShift(); static class Node { Node l, r; int value; int count; int heapValue; boolean reversed; public Node(int v) { value = v; heapValue = rand.next(); count = 1; } public void print(String prefix) { if (l != null) { l.print(prefix + " "); } System.out.println(prefix + "v="+value+"/r="+reversed); if (r != null) { r.print(prefix + " "); } } } Node root; public static Node update(Node a) { if (a == null) { return null; } pushDown(a); a.count = 1 + count(a.l) + count(a.r); return a; } public static void pushDown(Node a) { if (a.reversed) { Node tmp = a.l; a.l = a.r; a.r = tmp; reverse(a.l); reverse(a.r); a.reversed = false; } } public static int count(Node a) { return (a == null) ? 0 : a.count; } public static void reverse(Node a) { if (a != null) { a.reversed ^= true; } } /** * Grabs k-th node from given node. * * @param a * @param k * @return */ public static Node grab(Node a, int k) { if (a == null) { return null; } update(a); int l = count(a.l); if (k == l) { return a; } else if (k < l) { return grab(a.l, k); } else { return grab(a.r, k-l-1); } } /** * Merges two trees. * * @param a * @param b * @return merged root node */ public static Node merge(Node a, Node b) { if (a == null || b == null) { return a == null ? b : a; } update(a); update(b); if (a.heapValue < b.heapValue) { a.r = merge(a.r, b); return update(a); } else { b.l = merge(a, b.l); return update(b); } } /** * Splits tree at point k. [0, k), [k, n) * * @param a * @param k * @return */ public static Node[] split(Node a, int k) { if (a == null) { return new Node[]{null, null}; } update(a); if (k <= count(a.l)) { Node[] s = split(a.l, k); a.l = s[1]; return new Node[]{s[0], update(a)}; } else { Node[] s = split(a.r, k - count(a.l) - 1); a.r = s[0]; return new Node[]{update(a), s[1]}; } } /** * Inserts node v at point k. * * @param a * @param k * @return new tree */ public static Node insert(Node a, int k, Node v) { Node[] x = split(a, k); return merge(x[0], merge(v, x[1])); } /** * Erases node at point k. * * @param a * @param k * @return new tree */ public static Node erase(Node a, int k) { Node[] al = split(a, k); Node[] ar = split(al[1], 1); return merge(al[0], ar[1]); } /** * Reverses value at point [l, r) * * @param l * @param r */ public void reverse(int l, int r) { Node[] right = split(root, r); Node[] left = split(right[0], l); reverse(left[1]); root = merge(left[0], merge(left[1], right[1])); } /** * Returns size of the tree. * * @return size of the tree */ public int size() { return count(root); } /** * Adds new node value=v to the end of tree. * * @param v */ public void push(int v) { root = insert(root, INF, new Node(v)); } /** * Adds new node value=v to tree at k-th position. * * @param v */ public void push(int v, int k) { root = insert(root, k, new Node(v)); } /** * Removes k-th node from tree. * * @param k */ public void remove(int k) { root = erase(root, k); } /** * Get k-th node value * * @param k * @return */ public int get(int k) { Node n = grab(root, k); if (n == null) { return -INF; } return n.value; } } " description="値の反転ができるtreap" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.rbst_lazy_persistent" value="static class Node { static Random _rnd = new Random(1); Node left, right; long value; long lazyValue; long sum; int count; public Node(long v) { value = v; lazyValue = 0; Node.update(this); } public Node clone() { Node n = new Node(value); n.left = left; n.right = right; n.lazyValue = lazyValue; return update(n); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Node [value="); builder.append(value); builder.append(", count="); builder.append(count); builder.append(", plus="); builder.append(lazyValue); builder.append(", sum="); builder.append(sum); builder.append("]"); return builder.toString(); } static Node update(Node c) { if (c == null) { return null; } c.count = 1 + count(c.left) + count(c.right); c.sum = c.value + count(c) * c.lazyValue + sum(c.left) + sum(c.right); return c; } static Node propergate(Node c) { if (c == null) { return null; } if (c.lazyValue == 0) { return c.clone(); } Node nc = c.clone(); if (nc.left != null) { nc.left = c.left.clone(); nc.left.lazyValue += c.lazyValue; update(nc.left); } if (nc.right != null) { nc.right = c.right.clone(); nc.right.lazyValue += c.lazyValue; update(nc.right); } nc.value += nc.lazyValue; nc.lazyValue = 0; return update(nc); } static int count(Node c) { return c == null ? 0 : c.count; } static long sum(Node c) { return c == null ? 0 : c.sum; } static Node merge(Node a, Node b) { if (a == null) { return b; } if (b == null) { return a; } Node ac = propergate(a); Node bc = propergate(b); if (_rnd.nextInt(a.count + b.count) < a.count) { ac.right = merge(a.right, bc); return update(ac); } else { bc.left = merge(ac, bc.left); return update(bc); } } static Node[] split(Node c, int k) { if (c == null) { return new Node[2]; } if (k <= count(c.left)) { Node cc = propergate(c); Node[] s = split(cc.left, k); cc.left = s[1]; s[1] = update(cc); return s; } else { Node cc = propergate(c); Node[] s = split(cc.right, k - count(cc.left) - 1); cc.right = s[0]; s[0] = update(cc); return s; } } public static Node add(Node a, int l, int r, int v) { if(a == null || r <= 0 || count(a) <= l) { return a; } if(l <= 0 && count(a) <= r) { propergate(a); Node ac = a.clone(); ac.lazyValue += v; return update(ac); }else{ propergate(a); Node ac = a.clone(); if(0 < r && l < count(a.left)) { ac.left = add(a.left, l, r, v); } if(count(a.left)+1 < r && l < count(a)) { ac.right = add(a.right, l-count(a.left)-1, r-count(a.left)-1, v); } if(l <= count(a.left) && count(a.left) < r){ ac.value += v; } return update(ac); } } public static long sum(Node a, int l, int r) { if(a == null || r <= 0 || count(a) <= l) { return 0; } if(l <= 0 && count(a) <= r) { return a.sum; } else { long ret = 0; if(0 < r && l < count(a.left)) { ret += sum(a.left, l, r); } if(count(a.left)+1 < r && l < count(a)) { ret += sum(a.right, l-count(a.left)-1, r-count(a.left)-1); } if(l <= count(a.left) && count(a.left) < r){ ret += a.value; } ret += a.lazyValue * (Math.min(r, count(a)) - Math.max(0, l)); return ret; } } } " description="永続遅延評価平衡二分探索木" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.segment.purmp" value="import java.util.Arrays; /** * Segment tree (point update, range minimum query) */ public class SegmentTreePURMQ { int N; int M; int[] seg; public SegmentTreePURMQ(int[] data) { N = Integer.highestOneBit(data.length-1)<<2; M = (N >> 1) - 1; seg = new int[N]; Arrays.fill(seg, Integer.MAX_VALUE); for (int i = 0 ; i < data.length ; i++) { seg[M+i] = data[i]; } for (int i = M-1 ; i >= 0 ; i--) { seg[i] = compute(i); } } /** * Uodates value at position minIndexSum. * * @param idx * @param value */ public void update(int idx, int value) { seg[M+idx] = value; int i = M+idx; while (true) { i = (i-1) >> 1; seg[i] = compute(i); if (i == 0) { break; } } } private int compute(int i) { return Math.min(seg[i*2+1], seg[i*2+2]); } /** * Finds minimum value from range [l,r). * * @param l * @param r * @return minimum value */ public int min(int l, int r) { return min(l, r, 0, 0, M+1); } private int min(int l, int r, int idx, int fr, int to) { if (to <= l || r <= fr) { return Integer.MAX_VALUE; } if (l <= fr && to <= r) { return seg[idx]; } int med = (fr+to) / 2; int ret = Integer.MAX_VALUE; ret = Math.min(ret, min(l, r, idx*2+1, fr, med)); ret = Math.min(ret, min(l, r, idx*2+2, med, to)); return ret; } public int findIndexLessThanV(int l, int r, int v) { int ret = findIndexLessThanV(l, r, 0, 0, M+1, v); if (ret == Integer.MAX_VALUE) { return -1; } return ret; } private int findIndexLessThanV(int l, int r, int idx, int fr, int to, int v) { if (to <= l || r <= fr) { return Integer.MAX_VALUE; } if (seg[idx] > v) { return Integer.MAX_VALUE; } int med = (fr+to) / 2; if (l <= fr && to <= r) { int len = to-fr; if (len == 1) { return idx-M; } } int left = findIndexLessThanV(l, r, idx*2+1, fr, med, v); if (left < Integer.MAX_VALUE) { return left; } else { return findIndexLessThanV(l, r, idx*2+2, med, to, v); } } }" description="点更新・区間最小値" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.segment.rarmq" value="package data_structure.segment; import java.util.Arrays; /** * Segment tree (range add, range minimum query). */ public class SegmentTreeRARMQ { int N; int M; long[] segMin; long[] segAdd; public SegmentTreeRARMQ(long[] data) { N = Integer.highestOneBit(data.length-1)<<2; M = (N >> 1) - 1; segMin = new long[N]; segAdd = new long[N]; Arrays.fill(segMin, Long.MAX_VALUE); for (int i = 0 ; i < data.length ; i++) { segMin[M+i] = data[i]; } for (int i = M-1 ; i >= 0 ; i--) { segMin[i] = compute(i); } } public long compute(int i) { return Math.min(segMin[i*2+1], segMin[i*2+2]) + segAdd[i]; } public void add(int l, int r, long k) { add(l, r, k, 0, 0, M+1); } public void add(int l, int r, long x, int idx, int fr, int to) { if (to <= l || r <= fr) { return; } if (l <= fr && to <= r) { segAdd[idx] += x; while (idx >= 1) { idx = (idx - 1) / 2; segMin[idx] = Math.min(segMin[idx*2+1] + segAdd[idx*2+1], segMin[idx*2+2] + segAdd[idx*2+2]); } return; } int med = (fr + to) / 2; add(l, r, x, idx*2+1, fr, med); add(l, r, x, idx*2+2, med, to); } public long min(int l, int r) { return min(l, r, 0, 0, M+1); } public long min(int l, int r, int idx, int fr, int to) { if (to <= l || r <= fr) { return Long.MAX_VALUE; } if (l <= fr && to <= r) { return segMin[idx] + segAdd[idx]; } int med = (fr+to) / 2; long ret = Long.MAX_VALUE; ret = Math.min(ret, min(l, r, idx*2+1, fr, med)); ret = Math.min(ret, min(l, r, idx*2+2, med, to)); return ret + segAdd[idx]; } }" description="区間加算・区間最小値" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.segment.rursq" value="import java.util.Arrays; /** * Segment tree (range update, range sum query). */ public class SegmentTreeRURSQ { int N; int M; long[] segSum; long[] segUpd; public SegmentTreeRURSQ(long[] data) { N = Integer.highestOneBit(data.length-1)<<2; M = (N >> 1) - 1; segUpd = new long[N]; Arrays.fill(segUpd, -1); segSum = new long[N]; for (int i = 0 ; i < data.length ; i++) { segSum[M+i] = data[i]; } for (int i = M-1 ; i >= 0 ; i--) { segSum[i] = compute(i); } } public long compute(int i) { return segSum[i*2+1] + segSum[i*2+2]; } public void update(int l, int r, long k) { update(l, r, k, 0, 0, M+1); } public void propagate(int idx, int fr, int to) { if (segUpd[idx] != -1) { int l = idx*2+1; int r = idx*2+2; if (r < segUpd.length) { segUpd[l] = segUpd[idx]; segUpd[r] = segUpd[idx]; } segSum[idx] = (to-fr)*segUpd[idx]; segUpd[idx] = -1; } } public void update(int l, int r, long x, int idx, int fr, int to) { propagate(idx, fr, to); if (to <= l || r <= fr) { return; } if (l <= fr && to <= r) { segUpd[idx] = x; propagate(idx, fr, to); return; } int med = (fr + to) / 2; update(l, r, x, idx*2+1, fr, med); update(l, r, x, idx*2+2, med, to); // make sure that child nodes have been propagated. segSum[idx] = segSum[idx*2+1] + segSum[idx*2+2]; } public long sum(int l, int r) { return sum(l, r, 0, 0, M+1); } public long sum(int l, int r, int idx, int fr, int to) { propagate(idx, fr, to); if (to <= l || r <= fr) { return 0; } if (l <= fr && to <= r) { return segSum[idx]; } int med = (fr+to) / 2; long ret = sum(l, r, idx*2+1, fr, med) + sum(l, r, idx*2+2, med, to); // make sure that child nodes have been propagated. segSum[idx] = segSum[idx*2+1] + segSum[idx*2+2]; return ret; } } " description="区間更新・区間和" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="ds.unionfind" value="static class UnionFind { int[] rank; int[] parent; int[] cnt; public UnionFind(int n) { rank = new int[n]; parent = new int[n]; cnt = new int[n]; for (int i = 0; i < n ; i++) { parent[i] = i; cnt[i] = 1; } } public int find(int a) { if (parent[a] == a) { return a; } parent[a] = find(parent[a]); return parent[a]; } public void unite(int a, int b) { a = find(a); b = find(b); if (a == b) { return; } if (rank[a] < rank[b]) { parent[a] = b; cnt[b] += cnt[a]; cnt[a] = cnt[b]; } else { parent[b] = a; cnt[a] += cnt[b]; cnt[b] = cnt[a]; if (rank[a] == rank[b]) { rank[a]++; } } } public int groupCount(int a) { return cnt[find(a)]; } private boolean issame(int a, int b) { return find(a) == find(b); } } " description="素集合データ構造" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="geometry.closestpoint" value="static long closestDistance(long[][] points) { int n = points.length; if (n <= 1) { return -1; } Arrays.sort(points, (a, b) -> Long.signum(a[0] - b[0])); TreeSet<long[]> set = new TreeSet<>((a, b) -> { if (a[0] == b[0]) { return Long.signum(a[1] - b[1]); } return Long.signum(a[0] - b[0]); }); long best = dist2(points[0], points[1]); int idx = 0; for (int i = 0 ; i < n ; i++) { long sq = (long)Math.sqrt(best)+1; while (points[idx][0] + sq < points[i][0]) { set.remove(new long[]{ points[i][1], idx}); idx++; } long[] fr = set.higher(new long[]{ points[i][1]-sq, -1 }); long[] to = set.higher(new long[]{ points[i][1]+sq, -1 }); Set<long[]> pset = null; if (fr != null && to != null) { pset = set.subSet(fr, to); } else if (fr != null) { pset = set.tailSet(fr); } else if (to != null) { pset = set.headSet(to); } if (pset != null) { for (long[] p : pset) { int j = (int)p[1]; long d = dist2(points[i], points[j]); if (best > d) { best = d; } } } set.add(new long[]{ points[i][1], i }); } return best; } private static long dist2(long[] a, long[] b) { long dx = a[0]-b[0]; long dy = a[1]-b[1]; return dx*dx+dy*dy; } " description="最近対" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="geometry.convexhull" value="static class Point implements Comparable<Point> { long x; long y; Point(long _x, long _y) { x = _x; y = _y; } Point(Point a, Point b) { x = b.x - a.x; y = b.y - a.y; } public int compareTo(Point o) { if (x != o.x) { return Long.signum(x - o.x); } return Long.signum(y - o.y); } public long det(Point other) { return x * other.y - y * other.x; } public String toString() { return "(" + x + "," + y + ")"; } } public static List<Point> convexHull(Point[] points) { int n = points.length; Arrays.sort(points); Point[] candidate = new Point[n*2]; int k = 0; // downer for (int i = 0 ; i < n ; i++) { while (k > 1) { Point a = new Point(candidate[k-2], candidate[k-1]); Point b = new Point(candidate[k-1], points[i]); if (a.det(b) <= 0) { k--; } else { break; } } candidate[k++] = points[i]; } // upper int t = k; for (int i = n-2 ; i >= 0 ; i--) { while (k > t) { Point a = new Point(candidate[k-2], candidate[k-1]); Point b = new Point(candidate[k-1], points[i]); if (a.det(b) <= 0) { k--; } else { break; } } candidate[k++] = points[i]; } List<Point> ret = new ArrayList<Point>(); for (int i = 0 ; i < k - 1 ; i++) { ret.add(candidate[i]); } return ret; }" description="凸包" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="geometry_2dpoint" value="static class Point implements Comparable<Point> { long x; long y; public Point(long _x, long _y) { x = _x; y = _y; } long dot(Point o) { return x * o.x + y * o.y; } long cross(Point o) { return x * o.y - y * o.x; } Point to(Point o) { return new Point(o.x - x, o.y - y); } static boolean innerTriangle(Point x1, Point x2, Point x3, Point y) { Point v1 = x1.to(x2); Point v2 = x2.to(x3); Point v3 = x3.to(x1); Point u1 = x1.to(y); Point u2 = x2.to(y); Point u3 = x3.to(y); boolean c1 = v1.cross(u1) > 0; boolean c2 = v2.cross(u2) > 0; boolean c3 = v3.cross(u3) > 0; return c1 == c2 && c2 == c3; } @Override public int compareTo(Point o) { return x == o.x ? Long.compare(y, o.y) : Long.compare(x, o.x); } @Override public String toString() { return String.format("(%d,%d)", x, y); } }" description="二次元幾何" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.dijkstra" value="static class Dijkstra { int n; int[][][] graph; class State implements Comparable<State> { int now; long time; State(int n, long t) { now = n; time = t; } @Override public int compareTo(State o) { return Long.compare(time, o.time); } } public Dijkstra(int[][][] graph) { this.n = graph.length; this.graph = graph; } long[] doit(int from) { long[] dp = new long[n]; Arrays.fill(dp, Long.MAX_VALUE / 10); Queue<State> q = new PriorityQueue<>(); q.add(new State(from, 0)); dp[0] = 0; while (q.size() >= 1) { State st = q.poll(); for (int[] e : graph[st.now]) { long time = st.time + e[1]; if (dp[e[0]] > time) { dp[e[0]] = time; q.add(new State(e[0], time)); } } } return dp; } }" description="Dijkstra" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.flow.matching" value="public static class Matching { // Edmonds' cardinality matching algorithm. O(n^3) int[][] graph; int n; int[] mu; int[] phi; int[] rho; boolean[] scanned; public Matching(int[][] graph) { this.n = graph.length; this.graph = graph; mu = new int[n]; phi = new int[n]; rho = new int[n]; scanned = new boolean[n]; for (int i = 0; i < n ; i++) { mu[i] = phi[i] = rho[i] = i; } } public int[] solve() { int x = -1; while (true) { if (x == -1) { for (int i = 0; i < n; i++) { if (scanned[i]) { continue; } if (isEven(i)) { x = i; break; } } } if (x == -1) { break; } int y = -1; for (int to : graph[x]) { if (isOuter(to) || (isEven(to) && rho[to] != rho[x])) { y = to; } } if (y == -1) { scanned[x] = true; x = -1; } else if (isOuter(y)) { phi[y] = x; } else { int[] dx = new int[n]; int[] dy = new int[n]; Arrays.fill(dx, -1); Arrays.fill(dy, -1); for (int k = 0, w = x ; dx[w] < 0 ; w = (k % 2 == 1 ? mu[w] : phi[w])) { dx[w] = k++; } for (int k = 0, w = y ; dy[w] < 0 ; w = (k % 2 == 1 ? mu[w] : phi[w])) { dy[w] = k++; } boolean disjoint = true; for (int i = 0; i < n ; i++) { if (dx[i] >= 0 && dy[i] > 0) { disjoint = false; break; } } if (disjoint) { for (int v = 0; v < n ; v++) { if (dx[v] % 2 == 1) { mu[phi[v]] = v; mu[v] = phi[v]; } } for (int v = 0; v < n ; v++) { if (dy[v] % 2 == 1) { mu[phi[v]] = v; mu[v] = phi[v]; } } mu[x] = y; mu[y] = x; for (int v = 0; v < n ; v++) { phi[v] = rho[v] = v; scanned[v] = false; } x = -1; } else { int r = x; int d = n; for (int v = 0; v < n ; v++) { if (dx[v] >= 0 && dy[v] >= 0 && rho[v] == v && d > dx[v]) { d = dx[v]; r = v; } } for (int v = 0; v < n ; v++) { if (dx[v] <= d && dx[v] % 2 == 1 && rho[phi[v]] != r) { phi[phi[v]] = v; } } for (int v = 0; v < n ; v++) { if (dy[v] <= d && dy[v] % 2 == 1 && rho[phi[v]] != r) { phi[phi[v]] = v; } } if (rho[x] != r) { phi[x] = y; } if (rho[y] != r) { phi[y] = x; } for (int v = 0; v < n ; v++) { if (dx[rho[v]] >= 0 || dy[rho[v]] >= 0) { rho[v] = r; } } } } } return mu; } private boolean isEven(int idx) { return mu[idx] == idx || (mu[idx] != idx && phi[mu[idx]] != mu[idx]); } private boolean isOdd(int idx) { return mu[idx] != idx && phi[mu[idx]] == mu[idx] && phi[idx] != idx; } private boolean isOuter(int idx) { return mu[idx] != idx && phi[mu[idx]] == mu[idx] && phi[idx] == idx; } }" description="一般マッチング" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.flow.maxflow_dinic" value="public static class MaxFlowDinic { public List<int[]>[] graph; public int[] deg; public int[] level; public int[] itr; public int[] que; @SuppressWarnings("unchecked") public void init(int size) { graph = new List[size]; for (int i = 0; i < size ; i++) { graph[i] = new ArrayList<int[]>(); } deg = new int[size]; level = new int[size]; itr = new int[size]; que = new int[size+10]; } public void edge(int from, int to, int cap) { int fdeg = deg[from]; int tdeg = deg[to]; graph[from].add(new int[]{to, cap, tdeg}); graph[to].add(new int[]{from, 0, fdeg}); deg[from]++; deg[to]++; } public int dfs(int v, int t, int f) { if (v == t) return f; for (int i = itr[v] ; i < graph[v].size() ; i++) { itr[v] = i; int[] e = graph[v].get(i); if (e[1] > 0 && level[v] < level[e[0]]) { int d = dfs(e[0], t, Math.min(f, e[1])); if (d > 0) { e[1] -= d; graph[e[0]].get(e[2])[1] += d; return d; } } } return 0; } public void bfs(int s) { Arrays.fill(level, -1); int qh = 0; int qt = 0; level[s] = 0; que[qh++] = s; while (qt < qh) { int v = que[qt++]; for (int i = 0; i < graph[v].size() ; i++) { int[] e = graph[v].get(i); if (e[1] > 0 && level[e[0]] < 0) { level[e[0]] = level[v] + 1; que[qh++] = e[0]; } } } } public int max_flow(int s, int t) { int flow = 0; while (true) { bfs(s); if (level[t] < 0) { return flow; } Arrays.fill(itr, 0); while (true) { int f = dfs(s, t, Integer.MAX_VALUE); if (f <= 0) { break; } flow += f; } } } }" description="Dinicのアルゴリズムによる最大流" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.flow.maxflow_ford" value="public static class MaxFlowFord { public class Edge { int to; int cap; int rev; public Edge(int _to, int _cap, int _rev) { to = _to; cap = _cap; rev = _rev; } } public List<Edge>[] graph; public boolean[] used; @SuppressWarnings("unchecked") public void init(int size) { graph = new List[size]; for (int i = 0; i < size ; i++) { graph[i] = new ArrayList<Edge>(); } used = new boolean[size]; } public void edge(int from, int to, int cap) { graph[from].add(new Edge(to, cap, graph[to].size())); graph[to].add(new Edge(from, 0, graph[from].size() - 1)); } public int dfs(int v, int t, int f) { if (v == t) return f; used[v] = true; for (Edge e : graph[v]) { if (!used[e.to] && e.cap > 0) { int d = dfs(e.to, t, Math.min(f, e.cap)); if (d > 0) { e.cap -= d; graph[e.to].get(e.rev).cap += d; return d; } } } return 0; } public int max_flow(int s, int t) { int flow = 0; while (true) { used = new boolean[graph.length]; int f = dfs(s, t, Integer.MAX_VALUE); if (f == 0) { break; } flow += f; } return flow; } }" description="Ford-Fulkersonアルゴリズムによる最大流" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.flow.mincostflow" value="public static class MinCostFlow { public static class State implements Comparable<State> { int dist; int now; public State(int _n, int _d) { now = _n; dist = _d; } @Override public int compareTo(State o) { return dist - o.dist; } } public static class Edge { int to; int cap; int rev; int cost; public Edge(int _to, int _cap, int _cost, int _rev) { to = _to; cap = _cap; rev = _rev; cost = _cost; } } public static int INF = 1000000000; public static int V; public static int[] h; public static int[] dist; public static int[] prevv, preve; public static List<Edge>[] graph; @SuppressWarnings("unchecked") public static void init(int size) { graph = new List[size]; for (int i = 0 ; i < size ; i++) { graph[i] = new ArrayList<Edge>(); } dist = new int[size]; prevv = new int[size]; preve = new int[size]; h = new int[size]; V = size; } public static void edge(int from, int to, int cap, int cost) { graph[from].add(new Edge(to, cap, cost, graph[to].size())); graph[to].add(new Edge(from, 0, -cost, graph[from].size() - 1)); } public static long min_cost_flow_be(int s, int t, int f) { long res = 0; Arrays.fill(h, 0); // make sure that topo-sorted for (int i = 0; i < V ; i++) { for (Edge e : graph[i]) { if (e.cap >= 1) { h[e.to] = Math.min(h[e.to], h[i] + e.cost); } } } Queue<State> q = new PriorityQueue<State>(); while (f > 0) { q.clear(); Arrays.fill(dist, INF); dist[s] = 0; q.add(new State(s, 0)); while (q.size() >= 1) { State stat = q.poll(); int v = stat.now; if (dist[v] < stat.dist) { continue; } for (int i = 0 ; i < graph[v].size(); i++) { Edge e = graph[v].get(i); if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) { dist[e.to] = dist[v] + e.cost + h[v] - h[e.to]; prevv[e.to] = v; preve[e.to] = i; q.add(new State(e.to, dist[e.to])); } } } if (dist[t] == INF) { return res; } for (int v = 0 ; v < V ; v++) { h[v] += dist[v]; } long d = f; for (int v = t ; v != s ; v = prevv[v]) { d = Math.min(d, graph[prevv[v]].get(preve[v]).cap); } f -= d; res += d * h[t]; for (int v = t ; v != s ; v = prevv[v]) { Edge e = graph[prevv[v]].get(preve[v]); e.cap -= d; Edge rev = graph[v].get(e.rev); rev.cap += d; } } return res; } public static long min_cost_flow(int s, int t, int f) { long res = 0; Arrays.fill(h, 0); Queue<State> q = new PriorityQueue<State>(); while (f > 0) { q.clear(); Arrays.fill(dist, INF); dist[s] = 0; q.add(new State(s, 0)); while (q.size() >= 1) { State stat = q.poll(); int v = stat.now; if (dist[v] < stat.dist) { continue; } for (int i = 0 ; i < graph[v].size(); i++) { Edge e = graph[v].get(i); if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) { dist[e.to] = dist[v] + e.cost + h[v] - h[e.to]; prevv[e.to] = v; preve[e.to] = i; q.add(new State(e.to, dist[e.to])); } } } if (dist[t] == INF) { return res; } for (int v = 0 ; v < V ; v++) { h[v] += dist[v]; } long d = f; for (int v = t ; v != s ; v = prevv[v]) { d = Math.min(d, graph[prevv[v]].get(preve[v]).cap); } f -= d; res += d * h[t]; for (int v = t ; v != s ; v = prevv[v]) { Edge e = graph[prevv[v]].get(preve[v]); e.cap -= d; Edge rev = graph[v].get(e.rev); rev.cap += d; } } return res; } } " description="最小費用流" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.lowlink" value="static class LowLink { int n; int[] parent; int[] cnt; int[] ord; int[] low; int[][] graph; int[][] dfsTree; boolean[] root; int oi = 0; public LowLink(int[][] graph) { this.n = graph.length; this.parent = new int[n]; this.graph = graph; this.ord = new int[n]; this.low = new int[n]; this.root = new boolean[n]; this.cnt = new int[n]; this.dfsTree = new int[n][]; for (int i = 0; i < n ; i++) { this.dfsTree[i] = new int[graph[i].length]; Arrays.fill(this.dfsTree[i], -1); } Arrays.fill(parent, -1); Arrays.fill(ord, -1); Arrays.fill(low, n); } public void build() { for (int i = 0 ; i < n ; i++) { if (ord[i] == -1) { root[i] = true; // optional // dfsWithoutRecursive(i); dfs(i, -1); dfs0(i, -1); } } } private void dfsWithoutRecursive(int rt) { Stack<Integer> stk = new Stack<>(); stk.push(rt); stk.push(-1); stk.push(-1); List<Integer> vi = new ArrayList<>(); while (stk.size() >= 1) { int pid = stk.pop(); int par = stk.pop(); int now = stk.pop(); if (ord[now] != -1) { continue; } vi.add(now); if (pid >= 0) { dfsTree[par][pid] = now; } parent[now] = par; ord[now] = oi; low[now] = oi++; for (int i = 0 ; i < graph[now].length ; i++) { int to = graph[now][i]; if (to == par) { continue; } if (ord[to] == -1) { stk.push(to); stk.push(now); stk.push(i); } } } for (int i = vi.size()-1 ; i >= 0 ; i--) { int now = vi.get(i); cnt[now] = 1; for (int j = 0 ; j < graph[now].length ; j++) { int to = graph[now][j]; if (to == parent[now]) { // ignore parent edge continue; } if (dfsTree[now][j] != -1) { cnt[now] += cnt[dfsTree[now][j]]; low[now] = Math.min(low[now], low[dfsTree[now][j]]); } else { // that's a back edge! low[now] = Math.min(low[now], ord[to]); } } } } private void dfs(int now, int par) { if (ord[now] != -1) { return; } ord[now] = oi; low[now] = oi++; for (int i = 0 ; i < graph[now].length ; i++) { int to = graph[now][i]; if (to == par) { continue; } if (ord[to] == -1) { dfsTree[now][i] = to; dfs(to, now); low[now] = Math.min(low[now], low[to]); } else { // that's a back edge! low[now] = Math.min(low[now], ord[to]); } } } private void dfs0(int now, int par) { cnt[now] = 1; for (int to : dfsTree[now]) { if (to == -1 || to == par) { continue; } dfs0(to, now); cnt[now] += cnt[to]; } } private boolean isBridge(int u, int v) { return ord[u] < low[v]; } private boolean isArticulationPoint(int u) { if (root[u]) { int cn = 0; for (int to : dfsTree[u]) { if (to != -1) { cn++; } } return cn >= 2; } else { for (int to : dfsTree[u]) { if (to != -1 && ord[u] <= low[to]) { return true; } } return false; } } }" description="橋とか関節点とかを求めるやつ" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.minimumspanningarborscence" value="public class MinimumSpanningArborescence { int INF = 100000000; int n; int[][] graph; /** * @param adjacencyMatrix the graph represented */ public MinimumSpanningArborescence(int[][] adjacencyMatrix) { n = adjacencyMatrix.length; graph = adjacencyMatrix; } public int doit(int root) { int cost = 0; int[] c = doit(graph, root); int err = 0; for (int j = 0; j < n ; j++) { if (c[j] >= 0) { cost += graph[c[j]][j]; } else { err++; } } return err >= 2 ? -1 : cost; } private int[] doit(int[][] graph, int root) { int n = graph.length; int[] msa = new int[n]; Arrays.fill(msa, -1); for (int i = 0; i < n; i++) { if (i == root) { continue; } int min = INF; int e = -1; for (int j = 0; j < n; j++) { if (i == j) { continue; } if (min > graph[j][i]) { min = graph[j][i]; e = j; } } msa[i] = e; } int[] res = detectCycle(msa); if (res != null) { int cv = res[0]; int[] map = new int[n]; Arrays.fill(map,-1); int quo = n-res[1]; map[cv] = quo; int mincy = graph[msa[cv]][cv]; for (int k=msa[cv]; k!=cv; k=msa[k]) { map[k] = quo; mincy = Math.min(mincy, graph[msa[k]][k]); } int[] imap = new int[n-res[1]]; int ptr = 0; for (int i = 0; i < n; i++) { if (map[i] == quo) { continue; } map[i] = ptr; imap[ptr] = i; ptr++; } int[][] quog = new int[quo+1][quo+1]; for (int i = 0; i < quo+1; i++) { Arrays.fill(quog[i],INF); } int[] to = new int[n]; int[] from = new int[n]; for (int i = 0; i < n; i++) { if (map[i] != quo) { for (int j = 0; j < n; j++) { if (map[j] == quo) { int nc = graph[i][j] - graph[msa[j]][j] + mincy; if (quog[map[i]][quo] > nc) { quog[map[i]][quo] = nc; to[i] = j; } }else { quog[map[i]][map[j]] = graph[i][j]; } } } else { for (int j = 0; j < n; j++) { if (map[j] != quo) { int nc = graph[i][j]; if (quog[quo][map[j]] > nc) { quog[quo][map[j]] = nc; from[j] = i; } } } } } int[] quomsa = doit(quog, map[root]); for (int i = 0; i<quo; i++) { if (quomsa[i] == quo) { msa[imap[i]] = from[imap[i]]; } else if (quomsa[i] != -1) { msa[imap[i]] = imap[quomsa[i]]; } } int u = imap[quomsa[quo]]; msa[to[u]] = u; } return msa; } private int[] detectCycle(int[] f) { int n = f.length; BitSet visited = new BitSet(n); outer: for (int src = 0; src < n; src++) { if (visited.get(src) || f[src] < 0) { continue; } int power = 1; int lambda = 1; int tortoise = src; int hare = f[src]; visited.set(src); while (tortoise != hare) { if (hare < 0) { continue outer; } visited.set(hare); if (power == lambda) { tortoise = hare; power <<= 1; lambda = 0; } hare = f[hare]; lambda++; } if (lambda > 0) { return new int[]{hare, lambda}; } } return null; } }" description="最小有向全域木" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.minimumsteinertree" value="public class MinimumSteinerTree { private static final int INF = 100000000; public static int minimumSteinerTree(int[][] graph, int[] terminals) { int n = graph.length; int[][] dist = new int[n][n]; for (int i = 0; i < n ; i++) { dist[i] = graph[i].clone(); } for (int k = 0; k < n ; k++) { for (int i = 0; i < n ; i++) { for (int j = 0; j < n ; j++) { dist[i][j] = Math.min(dist[i][j], dist[i][k]+dist[k][j]); } } } int tn = terminals.length; int[][] opt = new int[1<<tn][n]; for (int i = 0; i < opt.length ; i++) { Arrays.fill(opt[i], INF); } for (int p = 0; p < tn ; p++) { for (int q = 0; q < n ; q++) { opt[1<<p][q] = dist[terminals[p]][q]; } } for (int s = 1; s < 1<<tn ; s++) { if ((s & (s-1)) == 0) { continue; } for (int p = 0 ; p < n ; p++) { for (int e = 0 ; e < s ; e++) { if ((e | s) == s) { opt[s][p] = Math.min(opt[s][p], opt[e][p] + opt[s-e][p]); } } } for (int p = 0 ; p < n ; p++) { for (int q = 0 ; q < n ; q++) { opt[s][p] = Math.min(opt[s][p], opt[s][q] + dist[p][q]); } } } int ans = INF; for (int s = 0 ; s < (1<<tn) ; s++) { for (int q = 0; q < n ; q++) { ans = Math.min(ans, opt[s][q] + opt[(1<<tn)-1-s][q]); } } return ans; } } " description="最小シュタイナー木" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.reverse_directedgraph" value="static int[][] reverseDirectedGraph(int[][] graph) { int n = graph.length; int[] deg = new int[n]; List<int[]> edges = new ArrayList<>(); for (int i = 0 ; i < n ; i++) { for (int j : graph[i]) { edges.add(new int[]{j, i}); deg[j]++; } } int[][] ret = new int[n][]; for (int i = 0 ; i < n ; i++) { ret[i] = new int[deg[i]]; } for (int[] edge : edges) { int a = edge[0]; int b = edge[1]; ret[a][--deg[a]] = b; } return ret; } " description="辺の向きを逆にしたグラフを作る" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.scc1" value="/** * Strongly connected component decomposition. */ public class SCC1 { boolean[] visited; int[] node_id; List<Integer> rev; int n; int[][] graph; int[][] r_graph; public SCC1(int[][] g) { n = g.length; graph = g; r_graph = new int[n][]; int[] deg = new int[n]; for (int i = 0 ; i < n ; i++) { for (int j : graph[i]) { deg[j]++; } } for (int i = 0 ; i < n ; i++) { r_graph[i] = new int[deg[i]]; } for (int i = 0 ; i < n ; i++) { for (int j : graph[i]) { r_graph[j][--deg[j]] = i; } } } public int[] scc() { visited = new boolean[n]; rev = new ArrayList<Integer>(); for (int i = 0; i<n; i++) { if (!visited[i]) { dfs(i); } } int id = 0; node_id = new int[n]; visited = new boolean[n]; for (int i = rev.size()-1; i>=0; i--) { if (!visited[rev.get(i)]) { rdfs(rev.get(i), id); id++; } } return node_id; } private void dfs(int i) { visited[i] = true; for (int next : graph[i]) { if (!visited[next]) { dfs(next); } } rev.add(i); } private void rdfs(int i, int id) { visited[i] = true; node_id[i] = id; for (int next : r_graph[i]) { if (!visited[next]) { rdfs(next, id); } } } } " description="Strongly Connected Component Decomposition" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.scc2" value="/** * Decompose graphs into component-bridge based tree. */ public class SCC2 { public static int[] decompose(int[][] graph) { int n = graph.length; boolean[] visited = new boolean[n]; int[] ord = new int[n]; int[] low = new int[n]; int[] ids = new int[n]; int[] inds = new int[n]; int[] parct = new int[n]; int pos = 0; for (int i = 0 ; i < n ; i++) { if (visited[i]) { continue; } ids[i] = i; inds[0] = 0; int sp = 1; while (sp > 0) { int cur = ids[sp-1]; if (inds[sp-1] == 0) { visited[cur] = true; ord[cur] = low[cur] = pos++; parct[sp-1] = 0; } if (inds[sp-1] == graph[cur].length) { if(sp-2 >= 0) { low[ids[sp-2]] = Math.min(low[ids[sp-2]], low[cur]); } sp--; continue; } int next = graph[cur][inds[sp-1]]; if (!visited[next]){ ids[sp] = next; inds[sp] = 0; inds[sp-1]++; sp++; continue; } else if (sp-2 >= 0 && (next != ids[sp-2] || ++parct[sp-1] >= 2)){ low[cur] = Math.min(low[cur], ord[next]); } inds[sp-1]++; } } int[] clus = new int[n]; Arrays.fill(clus, -1); int[] q = new int[n]; int cnum = 0; for (int i = 0 ; i < n ; i++){ if (clus[i] == -1){ int p = 0; q[p++] = i; clus[i] = cnum++; for(int r = 0;r < p;r++){ int cur = q[r]; for(int next : graph[cur]){ if(clus[next] == -1){ clus[next] = ord[cur] < low[next] ? cnum++ : clus[cur]; q[p++] = next; } } } } } return clus; } public static int[][] grouping(int[][] graph, int[] groups) { int n = graph.length; int gn = 0; for (int g : groups) { gn = Math.max(gn, g); } Set<Long> done = new HashSet<>(); List<Integer> edges = new ArrayList<>(); int[] deg = new int[gn+1]; for (int i = 0 ; i < n ; i++) { for (int j : graph[i]) { if (groups[i] != groups[j] && i < j) { int gfr = Math.min(groups[i], groups[j]); int gto = Math.max(groups[i], groups[j]); long eid = (((long) gfr)<<30)+gto; if (done.contains(eid)) { continue; } done.add(eid); edges.add(gfr); edges.add(gto); deg[gfr]++; deg[gto]++; } } } int[][] groupedGraph = new int[gn+1][]; for (int i = 0 ; i <= gn ; i++) { groupedGraph[i] = new int[deg[i]]; } int en = edges.size(); for (int i = 0 ; i < en ; i += 2) { int u = edges.get(i); int v = edges.get(i+1); groupedGraph[u][--deg[u]] = v; groupedGraph[v][--deg[v]] = u; } return groupedGraph; } } " description="Decompose graphs into component-bridge based tree." toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.scc3" value="/** * Decompose graph edges into components such that each component doesn't contain an articulation point. */ public class SCC3 { int n; int[] ord; int[] low; int[][] graph; boolean[] root; int oi = 0; Stack<int[]> tmpEdges; List<List<int[]>> edgeComponents; public SCC3(int[][] graph) { this.n = graph.length; this.graph = graph; this.ord = new int[n]; this.low = new int[n]; this.root = new boolean[n]; tmpEdges = new Stack<>(); edgeComponents = new ArrayList<>(); Arrays.fill(ord, -1); Arrays.fill(low, n); } public void build() { for (int i = 0 ; i < n ; i++) { if (ord[i] == -1) { root[i] = true; dfs(i, -1); } } } private void dfs(int now, int par) { if (ord[now] != -1) { return; } ord[now] = oi; low[now] = oi++; for (int i = 0 ; i < graph[now].length ; i++) { int to = graph[now][i]; if (to == par) { continue; } if (ord[to] < ord[now]) { tmpEdges.add(new int[]{now, to}); } if (ord[to] == -1) { dfs(to, now); low[now] = Math.min(low[now], low[to]); if (low[to] >= ord[now]) { List<int[]> edges = new ArrayList<>(); while (tmpEdges.size() >= 1) { int[] head = tmpEdges.pop(); edges.add(head); if (Math.min(head[0], head[1]) == Math.min(now, to)) { if (Math.max(head[0], head[1]) == Math.max(now, to)) { break; } } } edgeComponents.add(edges); } } else { // that's a back edge! low[now] = Math.min(low[now], ord[to]); } } } } " description="Decompose graph edges into components such that each component doesn't contain an articulation point." toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.topologicalsort1" value="static int[] toposort(int[][] graph) { int n = graph.length; int[] in = new int[n]; for (int i = 0 ; i < n ; i++) { for (int t : graph[i]) { in[t]++; } } Queue<Integer> q = new PriorityQueue<>(); int[] res = new int[n]; for (int i = 0 ; i < n ; i++) { if (in[i] == 0) { q.add(i); } } int idx = 0; while (q.size() >= 1) { int now = q.poll(); res[idx++] = now; for (int t : graph[now]) { in[t]--; if (in[t] == 0) { q.add(t); } } } for (int i = 0 ; i < n ; i++) { if (in[i] >= 1) { return null; } } return res; } " description="topological sort vertice of given graph" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.topologicalsort2" value="static int[] toposort(List<Integer>[] graph) { int n = graph.length; int[] in = new int[n]; for (int i = 0 ; i < n ; i++) { for (int t : graph[i]) { in[t]++; } } Queue<Integer> q = new PriorityQueue<>(); int[] res = new int[n]; for (int i = 0 ; i < n ; i++) { if (in[i] == 0) { q.add(i); } } int idx = 0; while (q.size() >= 1) { int now = q.poll(); res[idx++] = now; for (int t : graph[now]) { in[t]--; if (in[t] == 0) { q.add(t); } } } for (int i = 0 ; i < n ; i++) { if (in[i] >= 1) { return null; } } return res; } " toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.tree.eulertour" value="static class EulerTour { int n; int[][] graph; int[] parent; int[] ar; int[] cn; int ai = 0; public EulerTour(int[][] graph) { this.graph = graph; this.n = graph.length; this.parent = new int[n]; this.ar = new int[2*n]; this.cn = new int[n]; } private void go(int now) { ar[ai++] = now; int head = now; while (head != -1) { if (cn[head] != 0) { break; } ar[ai++] = -(head+1); head = parent[head]; if (head != -1) { cn[head]--; } } } private void parentChild(int root) { int[] que = new int[4*n]; int qh = 0; int qt = 0; que[qh++] = root; que[qh++] = -1; while (qt < qh) { int now = que[qt++]; int par = que[qt++]; parent[now] = par; for (int to : graph[now]) { if (to != par) { que[qh++] = to; que[qh++] = now; } } } for (int i = 0; i < n ; i++) { cn[i] = (parent[i] == -1) ? graph[i].length : graph[i].length-1; } } void build(int root) { parentChild(root); Stack<Integer> stk = new Stack<>(); ai = 0; stk.push(root); stk.push(-1); while (stk.size() >= 1) { int par = stk.pop(); int now = stk.pop(); go(now); for (int to : graph[now]) { if (to != par) { stk.push(to); stk.push(now); } } } } } " description="非再帰版EulerTour" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.tree.heavylightdecomposition" value="public class HeavyLightDecomposition { int n; int[][] graph; int root; int[] parent; int[] children; int[] level; int[] groupSize; int[] groupID; int[] groupLevel; public HeavyLightDecomposition(int[][] g, int rt) { n = g.length; graph = g; root = rt; parent = new int[n]; children = new int[n]; level = new int[n]; prec(); doit(); } public void prec() { int qh = 0, qt = 0; int[] que = new int[2*n]; que[qh++] = root; que[qh++] = -1; int[] ord = new int[n]; int oi = 0; while (qt < qh) { int now = que[qt++]; int par = que[qt++]; parent[now] = par; children[now]++; if (par != -1) { level[now] = level[par] + 1; } ord[oi++] = now; for (int to : graph[now]) { if (to != par) { que[qh++] = to; que[qh++] = now; } } } for (int i = n-1 ; i >= 0 ; i--) { int v = ord[i]; if (parent[v] != -1) { children[parent[v]] += children[v]; } } } public void doit() { int[] next = new int[n]; int[] groupHeads = new int[n]; groupHeads[0] = root; int gi = 1; for (int i = 0 ; i < n ; i++) { int max = -1; int maxJ = -1; for (int j = 0 ; j < graph[i].length ; j++) { int to = graph[i][j]; if (parent[i] != to) { if (max < children[to]) { max = children[to]; maxJ = j; } } } if (maxJ != -1) { next[i] = graph[i][maxJ]; for (int j = 0; j < graph[i].length; j++) { int to = graph[i][j]; if (parent[i] != to && j != maxJ) { groupHeads[gi++] = to; } } } else { next[i] = -1; } } groupID = new int[n]; groupLevel = new int[n]; groupSize = new int[gi]; for (int i = 0 ; i < gi ; i++) { int head = groupHeads[i]; groupID[head] = i; while (next[head] != -1) { int ne = next[head]; groupID[ne] = i; groupLevel[ne] = groupLevel[head] + 1; head = ne; } } for (int i = 0; i < n ; i++) { groupSize[groupID[i]]++; } } } " description="木の重軽分解" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.tree.lca" value="/** * Lowest common anscestor. */ public class LCA { int[][] graph; int[][] parent; int[] depth; public LCA(int[][] graph) { int n = graph.length; this.graph = graph; init(n); } void dfs(int now, int from, int dep) { parent[0][now] = from; depth[now] = dep; for (int to : graph[now]) { if (to != from) { dfs(to, now, dep+1); } } } void init(int n) { int log = 1; int nn = n; while (nn >= 1) { nn /= 2; log++; } parent = new int[log+1][n]; for (int i = 0 ; i <= log ; i++) { Arrays.fill(parent[i], -1); } depth = new int[n]; dfs(0, -1, 0); for (int k = 0 ; k < log ; k++) { for (int v = 0 ; v < n ; v++) { if (parent[k][v] < 0) { parent[k+1][v] = -1; } else { parent[k+1][v] = parent[k][parent[k][v]]; } } } } int lca(int u, int v) { int loglen = parent.length; if (depth[u] > depth[v]) { int tmp = u; u = v; v = tmp; } for (int k = 0 ; k < loglen ; k++) { if (((depth[v] - depth[u]) >> k) % 2 == 1) { v = parent[k][v]; } } if (u == v) { return u; } for (int k = loglen-1 ; k >= 0 ; k--) { if (parent[k][u] != parent[k][v]) { u = parent[k][u]; v = parent[k][v]; } } return parent[0][u]; } int dist(int x, int y) { int l = lca(x, y); return depth[x] + depth[y] - depth[l] * 2; } }" description="LCA" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.tree.parentcountorder" value="/** * Computes each node's {parent, number of vertices in its subtrees, BFS order} with given tree. * It returns array of size 3*n. * * O(n) * * @param graph * @param root * @return */ public static int[][] parentCountOrder(int[][] graph, int root) { int n = graph.length; int[] que = new int[2*n]; int[] parent = new int[n]; int[] bfsOrd = new int[n]; int[] cnt = new int[n]; int qh = 0, qt = 0; que[qh++] = root; que[qh++] = -1; int vi = 0; while (qt < qh) { int now = que[qt++]; int par = que[qt++]; parent[now] = par; bfsOrd[vi++] = now; for (int to : graph[now]) { if (to == par) { continue; } que[qh++] = to; que[qh++] = now; } } for (int i = n-1 ; i >= 0 ; i--) { int now = bfsOrd[i]; cnt[now]++; if (parent[now] != -1) { cnt[parent[now]] += cnt[now]; } } return new int[][]{ parent, cnt, bfsOrd }; } " description="根付き木の親、部分木のサイズ、行きがけ順を計算" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="graph.tree.tree_lca_query" value="static class TreeLCAQuery { LCA lca; int[] val; int[][] dbl; public TreeLCAQuery(LCA lca, int[] val) { int n = val.length; this.lca = lca; this.val = val; int lg = lca.parent.length; dbl = new int[lg][n]; for (int i = 0 ; i < n ; i++) { dbl[0][i] = val[i]; } for (int l = 1 ; l < lg ; l++) { for (int i = 0 ; i < n ; i++) { int half = lca.parent[l-1][i]; if (half >= 0) { dbl[l][i] = Math.min(dbl[l-1][i], dbl[l-1][half]); } else { dbl[l][i] = dbl[l-1][i]; } } } } public int min(int u, int v) { int min = Integer.MAX_VALUE; while (u != v) { int diff = lca.depth[u] - lca.depth[v]; int ctr = -1; while (diff > 0) { ctr++; diff /= 2; } min = Math.min(min, dbl[ctr][u]); u = lca.parent[ctr][u]; } min = Math.min(min, dbl[0][u]); return min; } } " description="ツリー上のクエリをLCAで解く" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="numeric.gcd" value="public static long gcd(long a, long b) { return b == 0 ? a : gcd(b, a%b); } " description="gcd" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="numeric.prime" value="/** * Computes Euler's totient function value of num : φ(num) * * O(sqrt(n)) * * @param num * @return */ static long totient(long num) { int[] primes = generatePrimes((int)Math.sqrt(num)+10); long ans = 1; for (long p : primes) { if (num < p) { break; } long pn = 1; while (num % p == 0) { pn *= p; num /= p; } ans *= (pn / p) * (p - 1); } if (num >= 2) { ans *= num - 1; } return ans; } /** * Generates primes less than upto. * * O(nlog(logn)) * * @param upto limit * @return array of primes */ static int[] generatePrimes(int upto) { boolean[] isp = new boolean[upto]; Arrays.fill(isp, true); isp[0] = isp[1] = false; int pi = 0; for (int i = 2; i < upto ; i++) { if (isp[i]) { pi++; for (int j = i * 2; j < upto; j += i) { isp[j] = false; } } } int[] ret = new int[pi]; int ri = 0; for (int i = 2 ; i < upto ; i++) { if (isp[i]) { ret[ri++] = i; } } return ret; } /** * Moebius function. Returns array of μ(n). * O(n) * * @param n limit * @return array of μ(n) */ public static int[] moebius(int n) { boolean[] isp = new boolean[n]; Arrays.fill(isp, true); isp[1] = isp[0] = false; for (int i = 2 ; i < isp.length ; i++) { if (isp[i]) { for (int ii = i*2 ; ii < isp.length ; ii += i) { isp[ii] = false; } } } int[] mb = new int[n]; Arrays.fill(mb, 1); for (int x = 1 ; x < mb.length ; x++) { if (isp[x]) { int cnt = 1; for (int xx = x ; xx < mb.length ; xx += x) { if (cnt % x == 0) { mb[xx] = 0; } else { mb[xx] *= -1; } cnt++; } } } return mb; }" description="totient,素数,moebius" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="string.suffix_array" value="static class SuffixArray { int n; char[] base; Integer[] sa; int[] rank; int[] tmp; int[] lcp; int compareNode(int i, int j, int k) { if (rank[i] != rank[j]) { return rank[i] - rank[j]; } else { int ri = i + k <= n ? rank[i+k] : -1; int rj = j + k <= n ? rank[j+k] : -1; return ri - rj; } } public SuffixArray(char[] x) { base = x; n = base.length; } void buildSA() { sa = new Integer[n+1]; rank = new int[n+1]; tmp = new int[n+1]; for (int i = 0 ; i <= n ; i++) { sa[i] = i; rank[i] = (i < n) ? base[i] : -1; } for (int _k = 1 ; _k <= n ; _k *= 2) { final int k = _k; Arrays.sort(sa, new Comparator<Integer>() { @Override public int compare(Integer i, Integer j) { return compareNode(i, j, k); } }); tmp[sa[0]] = 0; for (int i = 1 ; i <= n ; i++) { tmp[sa[i]] = tmp[sa[i-1]] + ((compareNode(sa[i-1], sa[i], k) < 0) ? 1 : 0); } for (int i = 0 ; i <= n ; i++) { rank[i] = tmp[i]; } } } void buildLCP() { for (int i = 0 ; i <= n ; i++) { rank[sa[i]] = i; } lcp = new int[n]; int h = 0; for (int i = 0 ; i < n ; i++) { int j = sa[rank[i]-1]; if (h > 0) { h--; } for (; j + h < n && i + h < n ; h++) { if (base[j+h] != base[i+h]) { break; } } lcp[rank[i]-1] = h; } } }" description="文字列の接尾辞配列" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="string.trie" value="public class PrefixAutomaton { int n; char[][] words; int[][] next; int[] parentId; int[] lastCharacter; int[] failure; int[] cnt; int[] hereCnt; int[] cmp; int ni; public PrefixAutomaton(char[][] words) { n = 1; this.words = words; for (int i = 0; i < words.length ; i++) { n += words[i].length; } next = new int[n+1][26]; parentId = new int[n+1]; lastCharacter = new int[n+1]; cnt = new int[n+1]; hereCnt = new int[n+1]; cmp = new int[n+1]; ni = 1; for (char[] w : words) { add(w); } buildFailureLink(); goup(); } public int go(char[] l) { int head = 0; for (int i = 0; i < l.length ; i++) { head = next[head][l[i]-'a']; } return head; } private void add(char[] c) { int head = 0; for (int i = 0; i < c.length ; i++) { int ci = c[i]-'a'; if (next[head][ci] == 0) { next[head][ci] = ni++; } parentId[next[head][ci]] = head; head = next[head][ci]; lastCharacter[head] = ci; } } private void buildFailureLink() { int[] que = new int[n]; int qh = 0; int qt = 0; que[qh++] = 0; failure = new int[n]; while (qt < qh) { int now = que[qt++]; if (parentId[now] >= 1) { int parFail = failure[parentId[now]]; failure[now] = next[parFail][lastCharacter[now]]; } for (int j = 0; j < 26 ; j++) { if (next[now][j] == 0) { next[now][j] = next[failure[now]][j]; } else { que[qh++] = next[now][j]; } } } } private void goup() { for (int i = ni-1 ; i >= 1 ; i--) { cnt[parentId[i]] += cnt[i]; } } public void compress() { for (int i = 1 ; i < ni ; i++) { int has = 0; int onlyID = -1; for (int k = 0 ; k < 26 ; k++) { if (next[i][k] != 0) { onlyID = next[i][k]; has++; } } if (has == 1 && hereCnt[i] == 0) { int my = lastCharacter[i]; next[parentId[i]][my] = onlyID; parentId[onlyID] = parentId[i]; lastCharacter[onlyID] = my; } } } }" description="Trie(Prefix automaton)" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="string.zfunction" value="/** * Computes z-function of given string a. * (z[idx] := longest common prefix of ([idx,n), [0,n)) * * @param a * @return */ public static int[] buildZ(char[] a) { int n = a.length; int[] z = new int[n]; if (n == 0) return z; z[0] = n; int l = 0, r = 0; for (int i = 1; i < n; i++) { if (i > r) { l = r = i; while (r < n && a[r - l] == a[r]) { r++; } z[i] = r - l; r--; } else { int k = i - l; if (z[k] < r - i + 1) { z[i] = z[k]; } else { l = i; while (r < n && a[r - l] == a[r]) { r++; } z[i] = r - l; r--; } } } return z; }" description="Z関数" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="tmpl" value="import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Arrays; import java.util.InputMismatchException; public class XXXXXX { public static void main(String[] args) { InputReader in = new InputReader(System.in); PrintWriter out = new PrintWriter(System.out); int x = in.nextInt(); out.println(x); out.flush(); } static class InputReader { private InputStream stream; private byte[] buf = new byte[1024]; private int curChar; private int numChars; public InputReader(InputStream stream) { this.stream = stream; } private int next() { if (numChars == -1) throw new InputMismatchException(); if (curChar >= numChars) { curChar = 0; try { numChars = stream.read(buf); } catch (IOException e) { throw new InputMismatchException(); } if (numChars <= 0) return -1; } return buf[curChar++]; } public int nextInt() { int c = next(); while (isSpaceChar(c)) c = next(); int sgn = 1; if (c == '-') { sgn = -1; c = next(); } int res = 0; do { if (c < '0' || c > '9') throw new InputMismatchException(); res *= 10; res += c - '0'; c = next(); } while (!isSpaceChar(c)); return res * sgn; } public long nextLong() { int c = next(); while (isSpaceChar(c)) c = next(); long sgn = 1; if (c == '-') { sgn = -1; c = next(); } long res = 0; do { if (c < '0' || c > '9') throw new InputMismatchException(); res *= 10; res += c - '0'; c = next(); } while (!isSpaceChar(c)); return res * sgn; } public boolean isSpaceChar(int c) { return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1; } public interface SpaceCharFilter { public boolean isSpaceChar(int ch); } } static void debug(Object... o) { System.err.println(Arrays.deepToString(o)); } } " description="solution template" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.convexhulltech" value="/** * Convex hull technique. * Given many lines(say y = a_{i} * x + b_{i}), computes many query: * what is the maximum y of current lines with given x? * * O(n+qlogn) where q = (number of queries), n = (maximum number of lines). */ public class ConvexHullTech { long[][] stk; int tail = 0; public ConvexHullTech(int maxLines) { stk = new long[maxLines][2]; } // add line : ax + b public void addLine(long a, long b) { stk[tail][0] = a; stk[tail][1] = b; tail++; while (tail >= 3 && compare(stk[tail-3], stk[tail-2], stk[tail-1])) { stk[tail-2][0] = stk[tail-1][0]; stk[tail-2][1] = stk[tail-1][1]; tail--; } } private boolean compare(long[] l1, long[] l2, long[] l3) { long a1 = l1[0]; long a2 = l2[0]; long a3 = l3[0]; long b1 = l1[1]; long b2 = l2[1]; long b3 = l3[1]; return (a2 - a1) * (b3 - b2) >= (a3 - a2) * (b2 - b1); } long val(int lidx, long x) { return stk[lidx][0] * x + stk[lidx][1]; } public long[] queryMax(long x) { int min = -1; int max = tail - 1; while (max - min > 1) { int med = (max + min) / 2; if (val(med, x) <= val(med+1, x)) { min = med; } else { max = med; } } return stk[max]; } public long computesMax(long x) { long[] line = queryMax(x); return line[0] * x + line[1]; } public long[] queryMin(long x) { int min = -1; int max = tail - 1; while (max - min > 1) { int med = (max + min) / 2; if (val(med, x) >= val(med+1, x)) { min = med; } else { max = med; } } return stk[max]; } public long computesMin(long x) { long[] line = queryMin(x); return line[0] * x + line[1]; } } " toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.countrangecoveringrange" value="/** * Counts how many ranges in [l,r). * Answers multiple query. * * O((n+q)logn) where q = query.length, n = ranges.length * * @param ranges array of [l,r) * @param query answerCountQuery query * @return answers to the queries */ public static int[] answerCountQuery(int[][] ranges, int[][] query) { int n = ranges.length; int q = query.length; int[][] qinfo = new int[q][3]; for (int i = 0; i < q ; i++) { qinfo[i] = new int[]{ query[i][0], query[i][1], i }; } Arrays.sort(qinfo, (q0, q1) -> q0[0] - q1[0]); Arrays.sort(ranges, (r0, r1) -> r0[0] - r1[0]); // it may need value compression. FenwickTree bit = new FenwickTree(1000010); for (int i = 0; i < n ; i++) { bit.add(ranges[i][1], 1); } int[] ans = new int[q]; int head = 0; for (int i = 0; i < q ; i++) { while (head < n && ranges[head][0] < qinfo[i][0]) { bit.add(ranges[head][1], -1); head++; } ans[qinfo[i][2]] = (int)bit.range(qinfo[i][0]+1, qinfo[i][1]); } return ans; } " toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.d4" value="private int[] dx = new int[]{0, -1, 0, 1}; private int[] dy = new int[]{-1, 0, 1, 0}; " description="direction four" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.dbg" value="public static void debug(Object... o) { System.err.println(Arrays.deepToString(o)); } " description="debug" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.dice" value="class Dice { final static int MAXCODE = 777; static enum Direction { LEFT(-1, 0), RIGHT(1, 0), UP(0, -1), DOWN(0, 1); int dx; int dy; Direction(int dx, int dy) { this.dx = dx; this.dy = dy; } } static int[][][][][] diceMap = new int[7][7][7][4][3]; static void buildDiceMap() { for (int i = 1 ; i <= 6 ; i++) { for (int j = 1 ; j <= 6 ; j++) { for (int k = 1 ; k <= 6 ; k++) { if (i == j || j == k || i == k) { continue; } Dice dice = new Dice(i, j, k); Dice[] dices = new Dice[]{dice.right(), dice.up(), dice.down(), dice.left()}; for (int d = 0 ; d < 4 ; d++) { Dice di = dices[d]; diceMap[i][j][k][d] = new int[]{di.top, di.up, di.right}; } } } } } int top; int up; int right; public Dice(int t, int u, int r) { top = t; up = u; right = r; } public String toString() { return String.format("%d/%d/%d", top, up, right); } public Dice move(Direction dir) { switch (dir) { case LEFT: return left(); case RIGHT: return right(); case UP: return up(); case DOWN: return down(); } throw new RuntimeException("invalid direction : " + dir); } private Dice left() { return new Dice(right, up, 7-top); } private Dice right() { return new Dice(7-right, up, top); } private Dice up() { return new Dice(7-up, top, right); } private Dice down() { return new Dice(up, 7-top, right); } public int encode() { return (top<<6)+(up<<3)+right; } public static Dice decode(int code) { int top = (code>>6)&7; int up = (code>>3)&7; int right = code&7; return new Dice(top, up, right); } public static Dice initialDice() { return new Dice(1, 2, 3); } }" description="サイコロ" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.distinctnumberrange1" value="/** * Computes distinct numbers of give array. * Answers multiple query. * * O(qlogn) where q = query.length, n = a.length. * * @param a array * @param query queries([l, r)) * @return answers to the queries */ public static int[] answerDistinctQuery(int[] a, int[][] query) { int n = a.length; int q = query.length; int[][] qinfo = new int[q][3]; for (int i = 0; i < q ; i++) { qinfo[i] = new int[]{query[i][0], query[i][1], i}; } Arrays.sort(qinfo, (o1, o2) -> o1[1] - o2[1]); // last index that number i appeared. // it may need value compression. int[] lastAppeared = new int[1000000]; Arrays.fill(lastAppeared, -1); FenwickTree bit = new FenwickTree(n+1); int head = 0; int[] ret = new int[q]; for (int i = 0; i < q ; i++) { while (head < qinfo[i][1]) { int num = a[head]; if (lastAppeared[num] != -1) { bit.set(lastAppeared[num]+1, 0); } lastAppeared[num] = head; bit.set(lastAppeared[num]+1, 1); head++; } ret[qinfo[i][2]] = (int)bit.range(qinfo[i][0]+1, qinfo[i][1]); } return ret; } " description="区間中のuniqueな数値を計上する" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.distinctnumberrange2" value="/** * Computes distinct numbers of give array. * Answers multiple query. * * O((n+q)(logn+logq)) where q = query.length, n = a.length. * * @refs https://twitter.com/uwitenpen/status/761777092069462016 * @param a array * @param query queries([l, r)) * @return answers to the queries */ public static int[] answerDistinctQuery(int[] a, int[][] query) { int n = a.length; // last index that number i appeared. // it may need value compression. int[] lastAppeared = new int[1000000]; Arrays.fill(lastAppeared, -1); // same number ranges. List<int[]> ranges = new ArrayList<>(); int[] ct = new int[1000000]; for (int i = 0; i < n ; i++) { ct[a[i]]++; if (lastAppeared[a[i]] == -1) { lastAppeared[a[i]] = i; continue; } ranges.add(new int[]{lastAppeared[a[i]], i+1}); lastAppeared[a[i]] = i; } int[][] ranges0 = new int[ranges.size()][]; for (int i = 0; i < ranges.size() ; i++) { ranges0[i] = ranges.get(i); } int[] coveringRanges = CountRangeCoveringRange.answerCountQuery(ranges0, query); int q = query.length; int[] ret = new int[q]; for (int i = 0; i < q ; i++) { ret[i] = (query[i][1] - query[i][0]) - coveringRanges[i]; } return ret; } " description="区間中のuniqueな数値を計上する(オンラインクエリ版)" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.io.buildgraph_edges_array" value="static int[][] buildGraph(int n, int[][] edges) { int m = edges.length; int[][] graph = new int[n][]; int[] deg = new int[n]; for (int i = 0 ; i < m ; i++) { int a = edges[i][0]; int b = edges[i][1]; deg[a]++; deg[b]++; } for (int i = 0 ; i < n ; i++) { graph[i] = new int[deg[i]]; } for (int i = 0 ; i < m ; i++) { int a = edges[i][0]; int b = edges[i][1]; graph[a][--deg[a]] = b; graph[b][--deg[b]] = a; } return graph; } " description="int[][] style" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.io.buildgraph_edges_list" value="static int[][] buildGraph(int n, List<int[]> edges) { int m = edges.size(); int[][] graph = new int[n][]; int[] deg = new int[n]; for (int i = 0 ; i < m ; i++) { int a = edges.get(i)[0]; int b = edges.get(i)[1]; deg[a]++; deg[b]++; } for (int i = 0 ; i < n ; i++) { graph[i] = new int[deg[i]]; } for (int i = 0 ; i < m ; i++) { int a = edges.get(i)[0]; int b = edges.get(i)[1]; graph[a][--deg[a]] = b; graph[b][--deg[b]] = a; } return graph; }" description="List<int[]> style" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.io.buildgraph_pair" value="static int[][] buildGraph(int[] l, int[] r) { int n = 0; for (int i = 0 ; i < l.length ; i++) { n = Math.max(n, l[i]); n = Math.max(n, r[i]); } int m = l.length; int[][] edges = new int[m][]; int[][] graph = new int[n][]; int[] deg = new int[n]; for (int i = 0 ; i < m ; i++) { deg[l[i]]++; deg[r[i]]++; edges[i] = new int[]{l[i], r[i]}; } for (int i = 0 ; i < n ; i++) { graph[i] = new int[deg[i]]; } for (int i = 0 ; i < m ; i++) { int a = edges[i][0]; int b = edges[i][1]; graph[a][--deg[a]] = b; graph[b][--deg[b]] = a; } return graph; }" description="int[] a, int[] b style" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.io.buildgraph_stdin" value="static int[][] buildGraph(InputReader in, int n, int m) { int[][] edges = new int[m][]; int[][] graph = new int[n][]; int[] deg = new int[n]; for (int i = 0 ; i < m ; i++) { int a = in.nextInt()-1; int b = in.nextInt()-1; deg[a]++; deg[b]++; edges[i] = new int[]{a, b}; } for (int i = 0 ; i < n ; i++) { graph[i] = new int[deg[i]]; } for (int i = 0 ; i < m ; i++) { int a = edges[i][0]; int b = edges[i][1]; graph[a][--deg[a]] = b; graph[b][--deg[b]] = a; } return graph; }" description="stdin style" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.io.buildweightedgraph_stdin" value="static int[][][] buildWeightedGraph(InputReader in, int n, int m) { int[][] edges = new int[m][]; int[][][] graph = new int[n][][]; int[] deg = new int[n]; for (int i = 0 ; i < m ; i++) { int a = in.nextInt()-1; int b = in.nextInt()-1; int w = in.nextInt(); deg[a]++; deg[b]++; edges[i] = new int[]{a, b, w}; } for (int i = 0 ; i < n ; i++) { graph[i] = new int[deg[i]][2]; } for (int i = 0 ; i < m ; i++) { int a = edges[i][0]; int b = edges[i][1]; int w = edges[i][2]; graph[a][--deg[a]][0] = b; graph[b][--deg[b]][0] = a; graph[a][deg[a]][1] = w; graph[b][deg[b]][1] = w; } return graph; }" description="stdin style" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.io.ir" value="public class InputReader { private static final int BUFFER_LENGTH = 1<<10; private InputStream stream; private byte[] buf = new byte[BUFFER_LENGTH]; private int curChar; private int numChars; public InputReader(InputStream stream) { this.stream = stream; } private int[] nextInts(int n) { int[] ret = new int[n]; for (int i = 0; i < n; i++) { ret[i] = nextInt(); } return ret; } private int[][] nextIntTable(int n, int m) { int[][] ret = new int[n][m]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { ret[i][j] = nextInt(); } } return ret; } private long[] nextLongs(int n) { long[] ret = new long[n]; for (int i = 0; i < n; i++) { ret[i] = nextLong(); } return ret; } private long[][] nextLongTable(int n, int m) { long[][] ret = new long[n][m]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { ret[i][j] = nextLong(); } } return ret; } private double[] nextDoubles(int n) { double[] ret = new double[n]; for (int i = 0; i < n; i++) { ret[i] = nextDouble(); } return ret; } private double[][] nextDoubleTable(int n, int m) { double[][] ret = new double[n][m]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { ret[i][j] = nextLong(); } } return ret; } private int next() { if (numChars == -1) { throw new InputMismatchException(); } if (curChar >= numChars) { curChar = 0; try { numChars = stream.read(buf); } catch (IOException e) { throw new InputMismatchException(); } if (numChars <= 0) return -1; } return buf[curChar++]; } public char nextChar() { int c = next(); while (isSpaceChar(c)) { c = next(); } if ('a' <= c && c <= 'z') { return (char) c; } if ('A' <= c && c <= 'Z') { return (char) c; } throw new InputMismatchException(); } public String nextToken() { int c = next(); while (isSpaceChar(c)) { c = next(); } StringBuilder res = new StringBuilder(); do { res.append((char) c); c = next(); } while (!isSpaceChar(c)); return res.toString(); } public int nextInt() { int c = skipWhileSpace(); int sgn = 1; if (c == '-') { sgn = -1; c = next(); } int res = 0; do { if (c < '0' || c > '9') { throw new InputMismatchException(); } res *= 10; res += c-'0'; c = next(); } while (!isSpaceChar(c)); return res*sgn; } public long nextLong() { int c = skipWhileSpace(); long sgn = 1; if (c == '-') { sgn = -1; c = next(); } long res = 0; do { if (c < '0' || c > '9') { throw new InputMismatchException(); } res *= 10; res += c-'0'; c = next(); } while (!isSpaceChar(c)); return res*sgn; } public double nextDouble() { // TODO: we should make some effort to handle this... return Double.valueOf(nextToken()); } public int skipWhileSpace() { int c = next(); while (isSpaceChar(c)) { c = next(); } return c; } public boolean isSpaceChar(int c) { return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1; } } " description="input reader" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.rand.xorshift" value="public class XorShift { private int x = 123456789; private int y = 362436069; private int z = 521288629; private int w = 88675123; public int nextInt(final int n) { final int t = x^(x<<11); x = y; y = z; z = w; w = (w^(w>>>19))^(t^(t>>>8)); final int r = w%n; return r < 0 ? r+n : r; } public int next() { final int t = x^(x<<11); x = y; y = z; z = w; w = w^(w>>>19)^(t^(t>>>8)); return w; } public double nextDouble() { return (double) (next()+(1L<<31))/(1L<<32); } public long nextLong() { return ((long) next()<<32)^(((long) next()<<32)>>>32); } } " description="XorShift" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.slideminvalue" value="/** * Computes slide-window min value. * Returns array of length (|a|-k+1), i-th element means min(a[i],a[i+1],...,a[i+k-1]). * * @param a original array * @param k window size * @return min values */ public static int[] slideMin(int[] a, int k) { int n = a.length; Deque<Integer> deq = new ArrayDeque<>(); int[] slideMin = new int[n-k+1]; for (int i = 0 ; i < n ; i++) { while (deq.size() >= 1 && a[deq.peekLast()] >= a[i]) { deq.pollLast(); } deq.add(i); if (i - k + 1 >= 0) { int top = deq.peekFirst(); slideMin[i-k+1] = a[top]; if (top == i - k + 1) { deq.pollFirst(); } } } return slideMin; }" description="スライド最小値" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="utils.stockspan" value="/** * For each i, computes the maximum position x s.t. a[x] >= a[i] and x < i. * If there is no such position, x will be -1. * * O(n) * * @param a * @return maximum position x for each i */ static int[] stockSpanLeft(int[] a) { int n = a.length; int head = 0; int[] stk = new int[n+1]; int[] L = new int[n]; for (int i = 0 ; i < n ; i++) { while (head >= 1 && a[i] > a[stk[head-1]]) { head--; } L[i] = (head >= 1) ? stk[head-1] : -1; stk[head++] = i; } return L; } /** * For each i, computes the minimum position x s.t. a[i] <= a[x] and i < x. * If there is no such position, x will be n. (n = a.length) * * O(n) * * @param a * @return minimum position x for each i */ static int[] stockSpanRight(int[] a) { int n = a.length; int head = 0; int[] stk = new int[n+1]; int[] R = new int[n]; for (int i = n-1 ; i >= 0 ; i--) { while (head >= 1 && a[i] > a[stk[head-1]]) { head--; } R[i] = (head >= 1) ? stk[head-1] : n; stk[head++] = i; } return R; }" description="Stock Span Problem" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>