public class Solution {
public static class SegmentTree {
private int MAXN;
private int[] arr;
private int[] sum;
private int[] lazy;
private int[] update;
private boolean[] isUpdate;
public SegmentTree(int[] origin) {
MAXN = origin.length + 1;
arr = new int[MAXN];
for (int i = 1; i < MAXN; i++) {
arr[i] = origin[i - 1];
}
sum = new int[MAXN << 2];
lazy = new int[MAXN << 2];
update = new int[MAXN << 2];
isUpdate = new boolean[MAXN << 2];
}
// fill all nodes of rt tree
public void build(int rt, int l, int r) {
// base case
if (l == r) {
// fill leaf node
sum[rt] = arr[l];
} else {
int m = (l + r) >> 1;
// fill all nodes of rt's left tree
build(rt << 1, l, m);
// fill all nodes of rt's right tree
build(rt << 1 | 1, m + 1, r);
// fill rt node
pushUp(rt);
}
}
public void pushUp(int rt) {
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
public void pushDown(int rt, int ln, int rn) {
if (isUpdate[rt]) {
sum[rt << 1] = ln * update[rt];
lazy[rt << 1] = 0;
update[rt << 1] = update[rt];
isUpdate[rt << 1] = true;
sum[rt << 1 | 1] = rn * update[rt];
lazy[rt << 1 | 1] = 0;
update[rt << 1 | 1] = update[rt];
isUpdate[rt << 1 | 1] = true;
}
if (lazy[rt] != 0) {
sum[rt << 1] += ln * lazy[rt];
lazy[rt << 1] += lazy[rt];
sum[rt << 1 | 1] += rn * lazy[rt];
lazy[rt << 1 | 1] += lazy[rt];
lazy[rt] = 0;
}
}
public void add(int rt, int l, int r, int L, int R, int C) {
// unique case
if (L <= l && R >= r) {
// update rt node
sum[rt] += (r - l + 1) * C;
lazy[rt] += C;
} else {
int m = (l + r) >> 1;
// push down lazy
pushDown(rt, m - l + 1, r - m);
if (L <= m) {
add(rt << 1, l, m, L, R, C);
}
if (R > m) {
add(rt << 1 | 1, m + 1, r, L, R, C);
}
// update rt node
pushUp(rt);
}
}
public void update(int rt, int l, int r, int L, int R, int C) {
// unique case
if (L <= l && R >= r) {
// update rt node
sum[rt] = (r - l + 1) * C;
lazy[rt] = 0;
update[rt] = C;
isUpdate[rt] = true;
} else {
int m = (l + r) >> 1;
// push down last lazy and change
pushDown(rt, m - l + 1, r - m);
if (L <= m) {
update(rt << 1, l, m, L, R, C);
}
if (R > m) {
update(rt << 1 | 1, m + 1, r, L, R, C);
}
// update rt node
pushUp(rt);
}
}
public long query(int rt, int l, int r, int L, int R) {
// unique case
if (L <= l && R >= r) {
return sum[rt];
}
int m = (l + r) >> 1;
pushDown(rt, m - l + 1, r - m);
long ans = 0;
if (L <= m) {
ans += query(rt << 1, l, m, L, R);
}
if (R > m) {
ans += query(rt << 1 | 1, m + 1, r, L, R);
}
return ans;
}
public int kthSmall(int rt, int l, int r, int k) {
// base case
if (l == r) {
return l;
}
int m = (l + r) >> 1;
pushDown(rt, m - l + 1, r - m);
long lSum = query(rt << 1, l, m, l, m);
if (k <= lSum) {
return kthSmall(rt << 1, l, m, k);
} else {
return kthSmall(rt << 1 | 1, m + 1, r, k);
}
}
public int kthBig(int rt, int l, int r, int k) {
// base case
if (l == r) {
return l;
}
int m = (l + r) >> 1;
pushDown(rt, m - l + 1, r - m);
long lSum = query(rt << 1, l, m, l, m);
if (k > lSum) {
return kthSmall(rt << 1, l, m, k);
} else {
return kthSmall(rt << 1 | 1, m + 1, r, k);
}
}
}
}