-
Notifications
You must be signed in to change notification settings - Fork 0
/
CircularRMQ.java
135 lines (126 loc) · 4.22 KB
/
CircularRMQ.java
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
/** #segment-tree */
import java.util.Scanner;
class CircularRMQ {
private static int INF = 1000000000;
private static double log2(int n) {
return Math.log(n) / Math.log(2);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
// height of segment tree
int h = (int) Math.ceil(log2(n));
// max size of segment tree
int sizeTree = 2 * (int) Math.pow(2, h) - 1;
int[] segmentTree = new int[sizeTree];
// build segment tree
buildTree(arr, segmentTree, 0, n - 1, 0);
int[] lazy = new int[sizeTree];
// query
int m = sc.nextInt();
sc.nextLine();
for (int q = 0; q < m; q++) {
String cmdLine = sc.nextLine();
String[] cmd = cmdLine.split(" ");
if (cmd.length == 2) { // rmg(lf, rg)
int lf = Integer.parseInt(cmd[0]);
int rg = Integer.parseInt(cmd[1]);
int result = INF;
if (lf <= rg) {
result = minRangeLazy(segmentTree, lazy, 0, n - 1, lf, rg, 0);
} else {
int tmp1 = minRangeLazy(segmentTree, lazy, 0, n - 1, lf, n - 1, 0);
int tmp2 = minRangeLazy(segmentTree, lazy, 0, n - 1, 0, rg, 0);
result = Math.min(tmp1, tmp2);
}
System.out.println(result);
} else { // inc(lf, rg, v)
int lf = Integer.parseInt(cmd[0]);
int rg = Integer.parseInt(cmd[1]);
int v = Integer.parseInt(cmd[2]);
if (lf <= rg) {
updateQueryMinRangeLazy(segmentTree, lazy, 0, n - 1, lf, rg, v, 0);
} else {
updateQueryMinRangeLazy(segmentTree, lazy, 0, n - 1, lf, n - 1, v, 0);
updateQueryMinRangeLazy(segmentTree, lazy, 0, n - 1, 0, rg, v, 0);
}
}
}
}
// build segment Tree
private static void buildTree(int[] arr, int[] segmentTree, int left, int right, int idx) {
if (left == right) {
segmentTree[idx] = arr[left];
return;
}
int mid = left + (right - left) / 2;
buildTree(arr, segmentTree, left, mid, 2 * idx + 1);
buildTree(arr, segmentTree, mid + 1, right, 2 * idx + 2);
segmentTree[idx] = Math.min(segmentTree[2 * idx + 1], segmentTree[2 * idx + 2]);
}
// update segmentTree with lazy propagation in range
private static void updateQueryMinRangeLazy(
int[] segmentTree, int[] lazy, int left, int right, int from, int to, int delta, int idx) {
if (left > right) {
return;
}
if (lazy[idx] != 0) {
segmentTree[idx] += lazy[idx];
if (left != right) { // not a leaf node
lazy[2 * idx + 1] += lazy[idx];
lazy[2 * idx + 2] += lazy[idx];
}
lazy[idx] = 0;
}
// no overlap condition
if (from > right || to < left) {
return;
}
// total overlap condition
if (from <= left && right <= to) {
segmentTree[idx] += delta;
if (left != right) {
lazy[2 * idx + 1] += delta;
lazy[2 * idx + 2] += delta;
}
return;
}
// otherwise partial overlap so look both left and right
int mid = left + (right - left) / 2;
updateQueryMinRangeLazy(segmentTree, lazy, left, mid, from, to, delta, 2 * idx + 1);
updateQueryMinRangeLazy(segmentTree, lazy, mid + 1, right, from, to, delta, 2 * idx + 2);
segmentTree[idx] = Math.min(segmentTree[2 * idx + 1], segmentTree[2 * idx + 2]);
}
// get minimum value with lazy propagation in range
private static int minRangeLazy(
int[] segmentTree, int[] lazy, int left, int right, int from, int to, int idx) {
if (left > right) {
return INF;
}
if (lazy[idx] != 0) {
segmentTree[idx] += lazy[idx];
if (left != right) { // not a leaf node
lazy[2 * idx + 1] += lazy[idx];
lazy[2 * idx + 2] += lazy[idx];
}
lazy[idx] = 0;
}
// no overlap
if (from > right || to < left) {
return INF;
}
// total overlap
if (from <= left && right <= to) {
return segmentTree[idx];
}
// partial overlap
int mid = left + (right - left) / 2;
return Math.min(
minRangeLazy(segmentTree, lazy, left, mid, from, to, 2 * idx + 1),
minRangeLazy(segmentTree, lazy, mid + 1, right, from, to, 2 * idx + 2));
}
}