Last active
April 12, 2019 04:09
-
-
Save kiritofeng/16b8875558d1028bd792dd5da2bc8db7 to your computer and use it in GitHub Desktop.
Wesley's Code Templates!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <const int MAXV> struct BidirectionalBFS { | |
int dist[MAXV], to[MAXV], q[MAXV], vis[MAXV], stamp = 0; vector<int> adj[MAXV]; pair<int, int> edgeOnPath; | |
void addBiEdge(int v, int w) { adj[v].push_back(w); adj[w].push_back(v); } | |
void clear(int V = MAXV) { stamp = 0; for (int i = 0; i < MAXV; i++) adj[i].clear(); } | |
int run(int V, int s, int t) { | |
if (s == t) return 0; | |
if (stamp == 0) fill(vis, vis + V, stamp); | |
stamp++; int front = 0, back = 0; dist[s] = dist[t] = 0; q[back++] = s; q[back++] = t; vis[s] = stamp; vis[t] = -stamp; | |
while (front < back) { | |
int v = q[front++]; | |
for (int w : adj[v]) { | |
if (vis[v] == -vis[w]) { edgeOnPath = make_pair(v, w); return dist[v] + dist[w] + 1; } | |
else if (vis[v] != vis[w]) { dist[w] = dist[v] + 1; vis[w] = vis[v]; to[w] = v; q[back++] = w; } | |
} | |
} | |
return -1; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <class T, const bool ONE_INDEXED, const int ...Args> struct FenwickTree { | |
T val; | |
void init() { val = 0; } | |
void update(T v) { val += v; } | |
T rsq() { return val; } | |
}; | |
template <class T, const bool ONE_INDEXED, const int MAXN, const int ...Ns> struct FenwickTree <T, ONE_INDEXED, MAXN, Ns...> { | |
FenwickTree<T, ONE_INDEXED, Ns...> BIT[MAXN]; | |
void init() { for (int i = 0; i < MAXN; i++) BIT[i].init(); } | |
template <class ...Args> void update(int i, Args ...args) { for (i += !ONE_INDEXED; i < MAXN; i += i & -i) BIT[i].update(args...); } | |
template <class ...Args> T rsq(int l, int r, Args ...args) { | |
T ret = 0; | |
for (r += !ONE_INDEXED; r > 0; r -= r & -r) ret += BIT[r].rsq(args...); | |
for (l -= ONE_INDEXED; l > 0; l -= l & -l) ret -= BIT[l].rsq(args...); | |
return ret; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define FACTOR 4 | |
struct Sqrt { | |
vector<vector<int>> a; | |
vector<int> prefixSZ; | |
int n; | |
Sqrt() : n(0) {} | |
template <typename It> | |
Sqrt(It st, It en) : n(en - st) { | |
int sqrtn = (int) sqrt(n) * FACTOR; | |
for (It i = st; i < en; i += sqrtn) { | |
a.emplace_back(i, min(i + sqrtn, en)); | |
prefixSZ.push_back(0); | |
} | |
for (int i = 1; i < (int) a.size(); i++) { | |
prefixSZ[i] = prefixSZ[i - 1] + (int) a[i - 1].size(); | |
} | |
} | |
void insert(int val) { | |
int lo = 0, hi = (int) a.size(), mid; | |
while (lo < hi) { | |
mid = lo + (hi - lo) / 2; | |
if (val < a[mid].back()) hi = mid; | |
else lo = mid + 1; | |
} | |
int i = lo; | |
if (lo != (int) a.size()) { | |
lo = 0, hi = (int) a[i].size(); | |
while (lo < hi) { | |
mid = lo + (hi - lo) / 2; | |
if (val < a[i][mid]) hi = mid; | |
else lo = mid + 1; | |
} | |
} | |
if (n++ == 0) { | |
a.emplace_back(); | |
prefixSZ.push_back(0); | |
} | |
if (i == (int) a.size()) a[--i].push_back(val); | |
else a[i].insert(a[i].begin() + lo, val); | |
int sqrtn = (int) sqrt(n) * FACTOR; | |
if ((int) a[i].size() > 2 * sqrtn) { | |
a.emplace(a.begin() + i + 1, a[i].begin() + sqrtn, a[i].end()); | |
a[i].resize(sqrtn); | |
prefixSZ.push_back(0); | |
} | |
for (int j = i + 1; j < (int) a.size(); j++) { | |
prefixSZ[j] = prefixSZ[j - 1] + (int) a[j - 1].size(); | |
} | |
} | |
bool erase(int val) { | |
int lo = 0, hi = (int) a.size(), mid; | |
while (lo < hi) { | |
mid = lo + (hi - lo) / 2; | |
if (a[mid].back() < val) lo = mid + 1; | |
else hi = mid; | |
} | |
if (lo == (int) a.size()) return false; | |
int i = lo; | |
lo = 0, hi = (int) a[i].size(); | |
while (lo < hi) { | |
mid = lo + (hi - lo) / 2; | |
if (a[i][mid] < val) lo = mid + 1; | |
else hi = mid; | |
} | |
if (a[i][lo] != val) return false; | |
--n; | |
a[i].erase(a[i].begin() + lo); | |
if (a[i].empty()) { | |
a.erase(a.begin() + i); | |
prefixSZ.pop_back(); | |
} | |
for (int j = i + 1; j < (int) a.size(); j++) { | |
prefixSZ[j] = prefixSZ[j - 1] + (int) a[j - 1].size(); | |
} | |
return true; | |
} | |
void pop_back() { | |
--n; | |
a.back().pop_back(); | |
if (a.back().empty()) { | |
a.pop_back(); | |
prefixSZ.pop_back(); | |
} | |
} | |
int back() { | |
return a.back().back(); | |
} | |
int at(int k) { | |
int lo = 0, hi = (int) (a.size()) - 1, mid; | |
while (lo <= hi) { | |
mid = lo + (hi - lo) / 2; | |
if (k < prefixSZ[mid]) hi = mid - 1; | |
else lo = mid + 1; | |
} | |
return a[hi][k - prefixSZ[hi]]; | |
} | |
int getRank(int val) { | |
int lo = 0, hi = (int) a.size(), mid; | |
while (lo < hi) { | |
mid = lo + (hi - lo) / 2; | |
if (a[mid].back() < val) lo = mid + 1; | |
else hi = mid; | |
} | |
if (lo == (int) a.size()) return -1; | |
int i = lo; | |
lo = 0, hi = (int) a[i].size(); | |
while (lo < hi) { | |
mid = lo + (hi - lo) / 2; | |
if (a[i][mid] < val) lo = mid + 1; | |
else hi = mid; | |
} | |
return a[i][lo] == val ? prefixSZ[i] + lo : -1; | |
} | |
void print() { | |
for (int i = 0; i < (int) a.size(); i++) { | |
for (int j = 0; j < (int) a[i].size(); j++) { | |
cout << a[i][j] << sp; | |
} | |
} | |
} | |
}; | |
#define MAXN 100005 | |
int N, M, A[MAXN]; | |
vector<Sqrt> a; | |
vector<int> prefixSZ; | |
int n; | |
void init() { | |
n = N; | |
int cbrtnsq = (int) cbrt(n) * cbrt(n) * FACTOR; | |
for (int i = 0; i < n; i += cbrtnsq) { | |
a.emplace_back(A + i, A + min(i + cbrtnsq, n)); | |
prefixSZ.push_back(0); | |
} | |
for (int i = 1; i < (int) a.size(); i++) { | |
prefixSZ[i] = prefixSZ[i - 1] + (int) a[i - 1].n; | |
} | |
} | |
void insert(int val) { | |
int lo = 0, hi = (int) a.size(), mid; | |
while (lo < hi) { | |
mid = lo + (hi - lo) / 2; | |
if (val < a[mid].back()) hi = mid; | |
else lo = mid + 1; | |
} | |
if (n++ == 0) { | |
a.emplace_back(); | |
prefixSZ.push_back(0); | |
} | |
if (lo == (int) a.size()) a[--lo].insert(val); | |
else a[lo].insert(val); | |
int cbrtnsq = (int) cbrt(n) * cbrt(n) * FACTOR; | |
if (a[lo].n > 2 * cbrtnsq) { | |
vector<int> b; | |
while (a[lo].n > cbrtnsq) { | |
b.push_back(a[lo].back()); | |
a[lo].pop_back(); | |
} | |
reverse(b.begin(), b.end()); | |
a.emplace(a.begin() + lo + 1, b.begin(), b.end()); | |
prefixSZ.push_back(0); | |
} | |
for (int j = lo + 1; j < (int) a.size(); j++) { | |
prefixSZ[j] = prefixSZ[j - 1] + (int) a[j - 1].n; | |
} | |
} | |
void erase(int val) { | |
int lo = 0, hi = (int) a.size(), mid; | |
while (lo < hi) { | |
mid = lo + (hi - lo) / 2; | |
if (a[mid].back() < val) lo = mid + 1; | |
else hi = mid; | |
} | |
if (lo == (int) a.size()) return; | |
if (!a[lo].erase(val)) return; | |
--n; | |
if (a[lo].n == 0) { | |
a.erase(a.begin() + lo); | |
prefixSZ.pop_back(); | |
} | |
for (int j = lo + 1; j < (int) a.size(); j++) { | |
prefixSZ[j] = prefixSZ[j - 1] + (int) a[j - 1].n; | |
} | |
} | |
int at(int k) { | |
int lo = 0, hi = ((int) a.size()) - 1, mid; | |
while (lo <= hi) { | |
mid = lo + (hi - lo) / 2; | |
if (k < prefixSZ[mid]) hi = mid - 1; | |
else lo = mid + 1; | |
} | |
return a[hi].at(k - prefixSZ[hi]); | |
} | |
int getRank(int val) { | |
int lo = 0, hi = (int) a.size(), mid; | |
while (lo < hi) { | |
mid = lo + (hi - lo) / 2; | |
if (a[mid].back() < val) lo = mid + 1; | |
else hi = mid; | |
} | |
if (lo == (int) a.size()) return -1; | |
int r = a[lo].getRank(val); | |
return r == -1 ? -1 : prefixSZ[lo] + r; | |
} | |
void print() { | |
for (int i = 0; i < (int) a.size(); i++) { | |
a[i].print(); | |
} | |
cout << nl; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <const int MAXN, const bool ONE_INDEXED> struct UnionFind { | |
int UF[MAXN], cnt; | |
void init(int N) { cnt = N; fill(UF, UF + N + ONE_INDEXED, -1); } | |
int find(int v) { return UF[v] < 0 ? v : UF[v] = find(UF[v]); } | |
bool join(int v, int w) { | |
if ((v = find(v)) == (w = find(w))) return false; | |
if (UF[v] > UF[w]) swap(v, w); | |
UF[v] += UF[w]; UF[w] = v; cnt--; return true; | |
} | |
bool connected(int v, int w) { return find(v) == find(w); } | |
int getSize(int v) { return -UF[find(v)]; } | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define INC 1 | |
#define ASSIGN 2 | |
int N, M, ROOT, VAL[MAXN], MN[MAXN], MX[MAXN], SUM[MAXN], LZ[MAXN], FL[MAXN], SZ[MAXN], L[MAXN], R[MAXN], P[MAXN]; | |
bool REV[MAXN]; | |
vector<int> adj[MAXN]; | |
void makeNode(int vert, int val) { | |
FL[vert] = LZ[vert] = L[vert] = R[vert] = P[vert] = 0; | |
REV[vert] = false; | |
VAL[vert] = SUM[vert] = MN[vert] = MX[vert] = val; | |
SZ[vert] = 1; | |
} | |
bool isRoot(int x) { | |
return !P[x] || (x != L[P[x]] && x != R[P[x]]); | |
} | |
int getSize(int x) { | |
return x ? SZ[x] : 0; | |
} | |
int getMin(int x) { | |
return x ? MN[x] : INT_MAX; | |
} | |
int getMax(int x) { | |
return x ? MX[x] : INT_MIN; | |
} | |
int getSum(int x) { | |
return x ? SUM[x] : 0; | |
} | |
int apply(int val, int lz, int fl) { | |
if (fl == ASSIGN) return lz; | |
else if (fl == INC) return val + lz; | |
else return val; | |
} | |
void propagate(int x) { | |
if (x) { | |
if (REV[x]) { | |
REV[x] ^= 1; | |
swap(L[x], R[x]); | |
if (L[x]) REV[L[x]] ^= 1; | |
if (R[x]) REV[R[x]] ^= 1; | |
} | |
VAL[x] = apply(VAL[x], LZ[x], FL[x]); | |
SUM[x] = apply(SUM[x], LZ[x] * SZ[x], FL[x]); | |
MN[x] = apply(MN[x], LZ[x], FL[x]); | |
MX[x] = apply(MX[x], LZ[x], FL[x]); | |
if (L[x]) { | |
LZ[L[x]] = apply(LZ[L[x]], LZ[x], FL[x]); | |
MAX(FL[L[x]], FL[x]); | |
} | |
if (R[x]) { | |
LZ[R[x]] = apply(LZ[R[x]], LZ[x], FL[x]); | |
MAX(FL[R[x]], FL[x]); | |
} | |
LZ[x] = FL[x] = 0; | |
} | |
} | |
void update(int x) { | |
if (x) { | |
SUM[x] = MN[x] = MX[x] = apply(VAL[x], LZ[x], FL[x]); | |
SZ[x] = 1; | |
if (L[x]) { | |
SUM[x] += apply(SUM[L[x]], apply(LZ[L[x]], LZ[x], FL[x]) * SZ[L[x]], max(FL[L[x]], FL[x])); | |
MIN(MN[x], apply(MN[L[x]], apply(LZ[L[x]], LZ[x], FL[x]), FL[L[x]])); | |
MAX(MX[x], apply(MX[L[x]], apply(LZ[L[x]], LZ[x], FL[x]), FL[L[x]])); | |
SZ[x] += SZ[L[x]]; | |
} | |
if (R[x]) { | |
SUM[x] += apply(SUM[R[x]], apply(LZ[R[x]], LZ[x], FL[x]) * SZ[R[x]], max(FL[R[x]], FL[x])); | |
MIN(MN[x], apply(MN[R[x]], apply(LZ[R[x]], LZ[x], FL[x]), FL[R[x]])); | |
MAX(MX[x], apply(MX[R[x]], apply(LZ[R[x]], LZ[x], FL[x]), FL[R[x]])); | |
SZ[x] += SZ[R[x]]; | |
} | |
} | |
} | |
void connect(int ch, int par, bool hasCh, bool isL) { | |
if (ch) P[ch] = par; | |
if (hasCh) { | |
if (isL) L[par] = ch; | |
else R[par] = ch; | |
} | |
} | |
void rotate(int x) { | |
int p = P[x]; | |
int g = P[p]; | |
bool isRootP = isRoot(p); | |
bool isL = x == L[p]; | |
connect(isL ? R[x] : L[x], p, true, isL); | |
connect(p, x, true, !isL); | |
connect(x, g, !isRootP, isRootP ? false : p == L[g]); | |
update(p); | |
} | |
void splay(int x) { | |
while (!isRoot(x)) { | |
int p = P[x]; | |
int g = P[p]; | |
if (!isRoot(p)) propagate(g); | |
propagate(p); | |
propagate(x); | |
if (!isRoot(p)) rotate((x == L[p]) == (p == L[g]) ? p : x); | |
rotate(x); | |
} | |
propagate(x); | |
update(x); | |
} | |
int expose(int x) { | |
int last = 0; | |
for (int y = x; y; y = P[y]) { | |
splay(y); | |
L[y] = last; | |
last = y; | |
} | |
splay(x); | |
return last; | |
} | |
void makeRoot(int x) { | |
expose(x); | |
REV[x] ^= 1; | |
} | |
int lca(int x, int y) { | |
makeRoot(ROOT); | |
expose(x); | |
return expose(y); | |
} | |
bool link(int x, int y) { | |
makeRoot(ROOT); | |
expose(x); | |
if (R[x]) return false; | |
P[x] = y; | |
return true; | |
} | |
bool cutParent(int x) { | |
makeRoot(ROOT); | |
expose(x); | |
if (!R[x]) return false; | |
R[x] = P[R[x]] = 0; | |
return true; | |
} | |
void update(int from, int to, int val, int fl) { | |
makeRoot(from); | |
expose(to); | |
LZ[to] = apply(LZ[to], val, fl); | |
MAX(FL[to], fl); | |
update(to); | |
} | |
int querySum(int from, int to) { | |
makeRoot(from); | |
expose(to); | |
return getSum(to); | |
} | |
int queryMin(int from, int to) { | |
makeRoot(from); | |
expose(to); | |
return getMin(to); | |
} | |
int queryMax(int from, int to) { | |
makeRoot(from); | |
expose(to); | |
return getMax(to); | |
} | |
void dfs(int v, int prev) { | |
for (int w : adj[v]) { | |
if (w == prev) continue; | |
assert(link(w, v)); | |
dfs(w, v); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class no_such_element_exception: public runtime_error { | |
public: | |
no_such_element_exception(): runtime_error("No such element exists"){} | |
no_such_element_exception(string message): runtime_error(message){} | |
}; | |
template <typename Value, typename Comparator = less<Value>> | |
struct RBTreeSet { | |
private: | |
Comparator cmp; | |
enum Color {BLACK = 0, RED = 1}; | |
/** | |
* Represents an inner node of the tree. | |
*/ | |
struct Node { | |
Value val; | |
bool color; | |
int size; | |
Node *left = nullptr, *right = nullptr; | |
Node(Value val, bool color, int size) { | |
this->val = val; | |
this->color = color; | |
this->size = size; | |
} | |
}; | |
/** | |
* The root node. | |
*/ | |
Node *root = nullptr; | |
/** | |
* Returns true if the node is red, false otherwise. | |
* | |
* @param x the node | |
* @return true if the node is red, false otherwise | |
*/ | |
bool isRed(Node *&x) { | |
if (x == nullptr) return false; | |
return x->color == RED; | |
} | |
/** | |
* Returns the number of nodes in the subtree. | |
* | |
* @param x the subtree | |
* @return the number of nodes in the subtree | |
*/ | |
int size(Node *&x) { | |
if (x == nullptr) return 0; | |
return x->size; | |
} | |
/** | |
* Updates the size and height of the subtree. | |
* | |
* @param x the subtree | |
*/ | |
void update(Node *&x) { | |
x->size = 1 + size(x->left) + size(x->right); | |
} | |
/** | |
* Flips the colors of the node and its children | |
* | |
* @param x the node to flip | |
*/ | |
void flipColors(Node *&x) { | |
x->color = !x->color; | |
x->left->color = !x->left->color; | |
x->right->color = !x->right->color; | |
} | |
/** | |
* Rotates the given subtree to the right. | |
* | |
* @param x the subtree | |
* @return the right rotated subtree | |
*/ | |
Node *rotateRight(Node *&x) { | |
Node *y = x->left; | |
x->left = y->right; | |
y->right = x; | |
y->color = y->right->color; | |
y->right->color = RED; | |
update(x); | |
update(y); | |
return y; | |
} | |
/** | |
* Rotates the given subtree to the left. | |
* | |
* @param x the subtree | |
* @return the left rotated subtree | |
*/ | |
Node *rotateLeft(Node *&x) { | |
Node *y = x->right; | |
x->right = y->left; | |
y->left = x; | |
y->color = y->left->color; | |
y->left->color = RED; | |
update(x); | |
update(y); | |
return y; | |
} | |
/** | |
* If x is red, and both x->left and x->left->left are black, | |
* make x->left or one of its children red. | |
* | |
* @param x the subtree | |
* @return updated subtree | |
*/ | |
Node *moveRedLeft(Node *&x) { | |
flipColors(x); | |
if (isRed(x->right->left)) { | |
x->right = rotateRight(x->right); | |
x = rotateLeft(x); | |
flipColors(x); | |
} | |
return x; | |
} | |
/** | |
* If x is red, and both x->right and x->right->left are black, | |
* make x->right or one of its children red. | |
* | |
* @param x the subtree | |
* @return updated subtree | |
*/ | |
Node *moveRedRight(Node *&x) { | |
flipColors(x); | |
if (isRed(x->left->left)) { | |
x = rotateRight(x); | |
flipColors(x); | |
} | |
return x; | |
} | |
/** | |
* Balances the red-black subtree. | |
* | |
* @param x the subtree | |
* @param fixRight whether a right-leaning fix is needed | |
* @return the balanced subtree | |
*/ | |
Node *balance(Node *&x, bool fixRight) { | |
if (isRed(x->right) && (!fixRight || !isRed(x->left))) x = rotateLeft(x); | |
if (isRed(x->left) && isRed(x->left->left)) x = rotateRight(x); | |
if (isRed(x->left) && isRed(x->right)) flipColors(x); | |
update(x); | |
return x; | |
} | |
// auxiliary function for contains | |
bool contains(Node *&x, Value val) { | |
if (x == nullptr) return false; | |
else if (cmp(val, x->val)) return contains(x->left, val); | |
else if (cmp(x->val, val)) return contains(x->right, val); | |
return true; | |
} | |
/** | |
* Inserts the specified value into the set, not allowing for duplicates. | |
* | |
* @param x the subtree | |
* @param val the value | |
* @return the subtree | |
*/ | |
Node *add(Node *&x, Value val) { | |
if (x == nullptr) return new Node(val, RED, 1); | |
if (cmp(val, x->val)) x->left = add(x->left, val); | |
else if (cmp(x->val, val)) x->right = add(x->right, val); | |
else return x; | |
update(x); | |
return balance(x, true); | |
} | |
/** | |
* Removes the smallest value from the given subtree. | |
* | |
* @param x the subtree | |
* @return the updated subtree | |
*/ | |
Node *removeMin(Node *&x, bool freeMemory) { | |
if (x->left == nullptr) { | |
if (freeMemory) delete x; | |
return nullptr; | |
} | |
if (!isRed(x->left) && !isRed(x->left->left)) x = moveRedLeft(x); | |
x->left = removeMin(x->left, freeMemory); | |
update(x); | |
return balance(x, false); | |
} | |
/** | |
* Removes the largest value from the given subtree. | |
* | |
* @param x the subtree | |
* @return the updated subtree | |
*/ | |
Node *removeMax(Node *&x, bool freeMemory) { | |
if (x->right == nullptr) { | |
if (freeMemory) delete x; | |
return nullptr; | |
} | |
if (!isRed(x->right) && !isRed(x->right->left)) x = moveRedRight(x); | |
x->right = removeMax(x->right, freeMemory); | |
update(x); | |
return balance(x, false); | |
} | |
/** | |
* Returns the node with the smallest value in the subtree. | |
* | |
* @param x the subtree | |
* @return the node with the smallest value in the subtree | |
*/ | |
Node *getMin(Node *&x) { | |
if (x->left == nullptr) return x; | |
return getMin(x->left); | |
} | |
/** | |
* Returns the node with the largest value in the subtree. | |
* | |
* @param x the subtree | |
* @return the node with the largest value in the subtree | |
*/ | |
Node *getMax(Node *&x) { | |
if (x->right == nullptr) return x; | |
return getMax(x->right); | |
} | |
/** | |
* Removes the specified value and its associated value from the given | |
* subtree. | |
* | |
* @param x the subtree | |
* @param val the value | |
* @return the updated subtree | |
*/ | |
Node *remove(Node *&x, Value val) { | |
if (cmp(val, x->val)) { | |
if (!isRed(x->left) && !isRed(x->left->left)) x = moveRedLeft(x); | |
x->left = remove(x->left, val); | |
} else { | |
if (isRed(x->left)) x = rotateRight(x); | |
if (!cmp(val, x->val) && !cmp(x->val, val) && x->right == nullptr) { | |
delete x; | |
return nullptr; | |
} | |
if (!isRed(x->right) && !isRed(x->right->left)) x = moveRedRight(x); | |
if (!cmp(val, x->val) && !cmp(x->val, val)) { | |
Node *y = getMin(x->right); | |
x->val = y->val; | |
x->right = removeMin(x->right, true); | |
} else { | |
x->right = remove(x->right, val); | |
} | |
} | |
update(x); | |
return balance(x, false); | |
} | |
/** | |
* Returns the node in the subtree with the largest value less than or equal | |
* to the given value. | |
* | |
* @param x the subtree | |
* @param val the value | |
* @return the node in the subtree with the largest value less than or equal | |
* to the given value | |
*/ | |
Node *floor(Node *&x, Value val) { | |
if (x == nullptr) return nullptr; | |
if (!cmp(val, x->val) && !cmp(x->val, val)) return x; | |
if (cmp(val, x->val)) return floor(x->left, val); | |
Node *y = floor(x->right, val); | |
if (y != nullptr) return y; | |
else return x; | |
} | |
/** | |
* Returns the node in the subtree with the smallest value greater than or | |
* equal to the given value. | |
* | |
* @param x the subtree | |
* @param val the value | |
* @return the node in the subtree with the smallest value greater than or | |
* equal to the given value | |
*/ | |
Node *ceiling(Node *&x, Value val) { | |
if (x == nullptr) return nullptr; | |
if (!cmp(val, x->val) && !cmp(x->val, val)) return x; | |
if (cmp(x->val, val)) return ceiling(x->right, val); | |
Node *y = ceiling(x->left, val); | |
if (y != nullptr) return y; | |
else return x; | |
} | |
/** | |
* Returns the node with value the kth smallest value in the subtree. | |
* | |
* @param x the subtree | |
* @param k the kth smallest value in the subtree | |
* @return the node with value the kth smallest value in the subtree | |
*/ | |
Node *select(Node *&x, int k) { | |
if (x == nullptr) return nullptr; | |
int t = size(x->left); | |
if (t > k) return select(x->left, k); | |
else if (t < k) return select(x->right, k - t - 1); | |
return x; | |
} | |
/** | |
* Returns the number of values in the subtree less than val. | |
* | |
* @param val the value | |
* @param x the subtree | |
* @return the number of values in the subtree less than val | |
*/ | |
int getRank(Node *&x, Value val) { | |
if (x == nullptr) return 0; | |
if (!cmp(x->val, val)) return getRank(x->left, val); | |
else return 1 + size(x->left) + getRank(x->right, val); | |
} | |
/** | |
* Adds the values in the subtree to queue following an in-order traversal. | |
* | |
* @param x the subtree | |
* @param queue the queue | |
*/ | |
void valuesInOrder(Node *&x, vector<Value> &queue) { | |
if (x == nullptr) return; | |
valuesInOrder(x->left, queue); | |
queue.push_back(x->val); | |
valuesInOrder(x->right, queue); | |
} | |
/** | |
* Adds the values between {@code lo} and {@code hi} in the subtree | |
* to the {@code queue}. | |
* | |
* @param x the subtree | |
* @param queue the queue | |
* @param lo the lowest value | |
* @param hi the highest value | |
*/ | |
void values(Node *&x, vector<Value> &queue, Value lo, Value hi) { | |
if (x == nullptr) return; | |
if (cmp(lo, x->val)) values(x->left, queue, lo, hi); | |
if (!cmp(x->val, lo) && !cmp(hi, x->val)) queue.push_back(x->val); | |
if (cmp(x->val, hi)) values(x->right, queue, lo, hi); | |
} | |
void print(Node *&x) { | |
if (x == nullptr) return; | |
print(x->left); | |
cout << x->val.f << ' '; | |
print(x->right); | |
} | |
/** | |
* Clears the symbol table. | |
* @param x the subtree | |
*/ | |
void clear(Node *x) { | |
if (x == nullptr) return; | |
clear(x->left); | |
clear(x->right); | |
delete x; | |
x = nullptr; | |
} | |
public: | |
/** | |
* Initializes an empty symbol table. | |
*/ | |
RBTreeSet() {} | |
/** | |
* Deletes the symbol table. | |
*/ | |
~RBTreeSet() { | |
clear(root); | |
} | |
/** | |
* Clears the symbol table. | |
*/ | |
void clear() { | |
clear(root); | |
root = nullptr; | |
} | |
/** | |
* Checks if the set is empty. | |
* | |
* @return {@code true} if the set is empty. | |
*/ | |
bool isEmpty() { | |
return root == nullptr; | |
} | |
/** | |
* Returns the number values in the set. | |
* | |
* @return the number values pairs in the set | |
*/ | |
int size() { | |
return size(root); | |
} | |
/** | |
* Checks if the set contains the given value. | |
* | |
* @param val the value | |
* @return {@code true} if the set contains {@code val} | |
* and {@code false} otherwise | |
*/ | |
bool contains(Value val) { | |
return contains(root, val); | |
} | |
/** | |
* Inserts the specified value into the set, allowing for duplicates. | |
* | |
* @param val the value | |
*/ | |
void add(Value val) { | |
root = add(root, val); | |
root->color = BLACK; | |
} | |
/** | |
* Removes the specified value from the set | |
* | |
* @param val the value | |
*/ | |
void remove(Value val) { | |
if (!contains(val)) return; | |
if (!isRed(root->left) && !isRed(root->right)) root->color = RED; | |
root = remove(root, val); | |
if (!isEmpty()) root->color = BLACK; | |
} | |
/** | |
* Removes the smallest value from the symbol table. | |
* | |
* @throws runtime_error if the symbol table is empty | |
*/ | |
void removeMin() { | |
if (isEmpty()) throw runtime_error("called removeMin() with empty symbol table"); | |
if (!isRed(root->left) && !isRed(root->right)) root->color = RED; | |
root = removeMin(root, true); | |
if (!isEmpty()) root->color = BLACK; | |
} | |
/** | |
* Removes the largest value from the symbol table. | |
* | |
* @throws runtime_error if the symbol table is empty | |
*/ | |
void removeMax() { | |
if (isEmpty()) throw runtime_error("called removeMax() with empty symbol table"); | |
if (!isRed(root->left) && !isRed(root->right)) root->color = RED; | |
root = removeMax(root, true); | |
if (!isEmpty()) root->color = BLACK; | |
} | |
/** | |
* Returns the smallest value in the set. | |
* | |
* @return the smallest value in the set | |
* @throws runtime_error if the set is empty | |
*/ | |
Value getMin() { | |
if (isEmpty()) throw runtime_error("called getMin() with empty set"); | |
return getMin(root)->val; | |
} | |
/** | |
* Returns the largest value in the set. | |
* | |
* @return the largest value in the set | |
* @throws runtime_error if the set is empty | |
*/ | |
Value getMax() { | |
if (isEmpty()) throw runtime_error("called getMax() with empty set"); | |
return getMax(root)->val; | |
} | |
/** | |
* Returns the largest value in the set less than or equal to {@code val}. | |
* | |
* @param val the value | |
* @return the largest value in the set less than or equal to {@code val} | |
* @throws runtime_error if the set is empty | |
* @throws no_such_element_exception if there is no value in the set less than or equal to {@code val} | |
*/ | |
Value floor(Value val) { | |
if (isEmpty()) throw runtime_error("called floor() with empty set"); | |
Node *x = floor(root, val); | |
if (x == nullptr) throw no_such_element_exception("call to floor() resulted in no such value"); | |
return x->val; | |
} | |
/** | |
* Returns the smallest value in the set greater than or equal to {@code val}. | |
* | |
* @param val the value | |
* @return a pair containing the smallest value in the set greater than or equal to {@code val} | |
* @throws runtime_error if the set is empty | |
* @throws no_such_element_exception if there is no value in the set greater than or equal to {@code val} | |
*/ | |
Value ceiling(Value val) { | |
if (isEmpty()) throw runtime_error("called ceiling() with empty set"); | |
Node *x = ceiling(root, val); | |
if (x == nullptr) throw no_such_element_exception("call to ceiling() resulted in no such value"); | |
return x->val; | |
} | |
/** | |
* Returns the kth smallest value in the set. | |
* | |
* @param k the order statistic | |
* @return the kth smallest value in the set | |
* @throws invalid_argument unless {@code k} is between 0 and | |
* {@code size() -1 } | |
*/ | |
Value select(int k) { | |
if (k < 0 || k >= size()) throw invalid_argument("k is not in range 0 to size"); | |
return select(root, k)->val; | |
} | |
/** | |
* Returns the number of values in the set strictly less than | |
* {@code val}. | |
* | |
* @param val the value | |
* @return the number of values in the set strictly less than | |
* {@code val} | |
*/ | |
int getRank(Value val) { | |
return getRank(root, val); | |
} | |
/** | |
* Returns all values in the set following an in-order traversal. | |
* | |
* @return all values in the set following an in-order traversal | |
*/ | |
vector<Value> values() { | |
vector<Value> queue; | |
valuesInOrder(root, queue); | |
return queue; | |
} | |
/** | |
* Returns all values in the set in the given range. | |
* | |
* @param lo the lowest value | |
* @param hi the highest value | |
* @return all value in the set between {@code lo} (inclusive) | |
* and {@code hi} (exclusive) | |
*/ | |
vector<Value> values(Value lo, Value hi) { | |
vector<Value> queue; | |
values(root, queue, lo, hi); | |
return queue; | |
} | |
void print() { | |
print(root); | |
} | |
/** | |
* Returns the number of values in the set in the given range. | |
* | |
* @param lo minimum endpoint | |
* @param hi maximum endpoint | |
* @return the number of values in the set between {@code lo} | |
* (inclusive) and {@code hi} (exclusive) | |
*/ | |
int size(Value lo, Value hi) { | |
if (cmp(hi, lo)) return 0; | |
if (contains(hi)) return getRank(hi) - getRank(lo) + 1; | |
else return getRank(hi) - getRank(lo); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class no_such_element_exception: public runtime_error { | |
public: | |
no_such_element_exception(): runtime_error("No such element exists"){} | |
no_such_element_exception(string message): runtime_error(message){} | |
}; | |
// Size Balanced Binary Search (Multi) Set | |
// Time Complexity: | |
// constructor, empty, size: O(1) | |
// values: O(N) | |
// all other operators: O(log N) | |
// Memory Complexity: O(N) | |
template <class Value, class Comparator = less<Value>> struct SBTSet { | |
struct Node { | |
int l, r, size; Value val; | |
Node(const Value &val) : l(-1), r(-1), size(1), val(val) {} | |
}; | |
int root = -1; vector<Node> T; Comparator cmp; | |
int Size(int x) { return x == -1 ? 0 : T[x].size; } | |
void update(int x) { T[x].size = 1 + Size(T[x].l) + Size(T[x].r); } | |
int rotateRight(int x) { int y = T[x].l; T[x].l = T[y].r; T[y].r = x; update(x); update(y); return y; } | |
int rotateLeft(int x) { int y = T[x].r; T[x].r = T[y].l; T[y].l = x; update(x); update(y); return y; } | |
int maintain(int x, bool flag) { | |
if (flag) { | |
if (T[x].r == -1) return x; | |
else if (Size(T[x].l) < Size(T[T[x].r].l)) { T[x].r = rotateRight(T[x].r); x = rotateLeft(x); } | |
else if (Size(T[x].l) < Size(T[T[x].r].r)) x = rotateLeft(x); | |
else return x; | |
} else { | |
if (T[x].l == -1) return x; | |
else if (Size(T[x].r) < Size(T[T[x].l].r)) { T[x].l = rotateLeft(T[x].l); x = rotateRight(x); } | |
else if (Size(T[x].r) < Size(T[T[x].l].l)) x = rotateRight(x); | |
else return x; | |
} | |
T[x].l = maintain(T[x].l, false); T[x].r = maintain(T[x].r, true); x = maintain(x, true); x = maintain(x, false); return x; | |
} | |
bool contains(int x, const Value &val) { | |
if (x == -1) return false; | |
else if (cmp(val, T[x].val)) return contains(T[x].l, val); | |
else if (cmp(T[x].val, val)) return contains(T[x].r, val); | |
return true; | |
} | |
int add(int x, const Value &val) { | |
if (x == -1) { T.emplace_back(val); return int(T.size()) - 1; } | |
if (cmp(val, T[x].val)) { int l = add(T[x].l, val); T[x].l = l; } | |
else { int r = add(T[x].r, val); T[x].r = r; } | |
update(x); return maintain(x, !cmp(val, T[x].val)); | |
} | |
int removeMin(int x) { | |
if (T[x].l == -1) return T[x].r; | |
T[x].l = removeMin(T[x].l); update(x); return x; | |
} | |
int removeMax(int x) { | |
if (T[x].r == -1) return T[x].l; | |
T[x].r = removeMax(T[x].r); update(x); return x; | |
} | |
int getMin(int x) { return T[x].l == -1 ? x : getMin(T[x].l); } | |
int getMax(int x) { return T[x].r == -1 ? x : getMax(T[x].r); } | |
int remove(int x, const Value &val) { | |
if (cmp(val, T[x].val)) T[x].l = remove(T[x].l, val); | |
else if (cmp(T[x].val, val)) T[x].r = remove(T[x].r, val); | |
else { | |
if (T[x].l == -1) return T[x].r; | |
else if (T[x].r == -1) return T[x].l; | |
else { int y = x; x = getMin(T[y].r); T[x].r = removeMin(T[y].r); T[x].l = T[y].l; } | |
} | |
update(x); return x; | |
} | |
int floor(int x, const Value &val) { | |
if (x == -1) return 0; | |
if (!cmp(val, T[x].val) && !cmp(T[x].val, val)) return x; | |
if (cmp(val, T[x].val)) return floor(T[x].l, val); | |
int y = floor(T[x].r, val); return y == -1 ? x : y; | |
} | |
int ceiling(int x, const Value &val) { | |
if (x == -1) return 0; | |
if (!cmp(val, T[x].val) && !cmp(T[x].val, val)) return x; | |
if (cmp(T[x].val, val)) return ceiling(T[x].r, val); | |
int y = ceiling(T[x].l, val); return y == -1 ? x : y; | |
} | |
int select(int x, int k) { | |
if (x == -1) return 0; | |
int t = Size(T[x].l); | |
if (t > k) return select(T[x].l, k); | |
else if (t < k) return select(T[x].r, k - t - 1); | |
return x; | |
} | |
int getRank(int x, const Value &val) { // number of values less than first occurrence | |
if (x == -1) return 0; | |
if (!cmp(T[x].val, val)) return getRank(T[x].l, val); | |
else return 1 + Size(T[x].l) + getRank(T[x].r, val); | |
} | |
void valuesInOrder(int x, vector<Value> &queue) { | |
if (x == -1) return; | |
valuesInOrder(T[x].l, queue); queue.push_back(T[x].val); valuesInOrder(T[x].r, queue); | |
} | |
void values(int x, vector<Value> &queue, const Value &lo, const Value &hi) { | |
if (x == -1) return; | |
if (cmp(lo, T[x].val)) values(T[x].l, queue, lo, hi); | |
if (!cmp(T[x].val, lo) && !cmp(hi, T[x].val)) queue.push_back(T[x].val); | |
if (cmp(T[x].val, hi)) values(T[x].r, queue, lo, hi); | |
} | |
void clear() { root = 0; T.clear(); } | |
bool empty() { return root == 0; } | |
int size() { return Size(root); } | |
bool contains(const Value &val) { return contains(root, val); } | |
void add(const Value &val) { root = add(root, val); } | |
void remove(const Value &val) { if (contains(val)) root = remove(root, val); } | |
void removeMin() { | |
if (empty()) throw runtime_error("called removeMin() with empty symbol table"); | |
root = removeMin(root); | |
} | |
void removeMax() { | |
if (empty()) throw runtime_error("called removeMax() with empty symbol table"); | |
root = removeMax(root); | |
} | |
Value getMin() { | |
if (empty()) throw runtime_error("called getMin() with empty symbol table"); | |
return T[getMin(root)].val; | |
} | |
Value getMax() { | |
if (empty()) throw runtime_error("called getMax() with empty symbol table"); | |
return T[getMax(root)].val; | |
} | |
Value floor(const Value &val) { | |
if (empty()) throw runtime_error("called floor() with empty symbol table"); | |
int x = floor(root, val); | |
if (x == -1) throw no_such_element_exception("call to floor() resulted in no such value"); | |
return T[x].val; | |
} | |
Value ceiling(const Value &val) { | |
if (empty()) throw runtime_error("called ceiling() with empty symbol table"); | |
int x = ceiling(root, val); | |
if (x == -1) throw no_such_element_exception("call to ceiling() resulted in no such value"); | |
return T[x].val; | |
} | |
Value select(int k) { | |
if (k < 0 || k >= size()) throw invalid_argument("k is not in range 0 to size"); | |
return T[select(root, k)].val; | |
} | |
int getRank(const Value &val) { return getRank(root, val); } | |
vector<Value> values() { vector<Value> queue; valuesInOrder(root, queue); return queue; } | |
vector<Value> values(const Value &lo, const Value &hi) { vector<Value> queue; values(root, queue, lo, hi); return queue; } | |
int size(const Value &lo, const Value &hi) { | |
if (cmp(hi, lo)) return 0; | |
else if (contains(hi)) return getRank(hi) - getRank(lo) + 1; | |
else return getRank(hi) - getRank(lo); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Node { | |
Node *l, *r, *p; int size, val; | |
Node(int val = 0) : l(nullptr), r(nullptr), p(nullptr), size(1), val(val) {} | |
void update(); | |
void rotate(Node *rootP); | |
void splay(Node *rootP); | |
}; | |
int Size(Node *x) { return x ? x->size : 0; } | |
void Node::update() { size = 1 + Size(l) + Size(r); } | |
void connect(Node *ch, Node *par, bool isL) { | |
if (ch) ch->p = par; | |
if (par) { | |
if (isL) par->l = ch; | |
else par->r = ch; | |
} | |
} | |
void Node::rotate(Node *rootP) { | |
Node *p = this->p, *g = p->p; bool isRootP = g == rootP, isL = this == p->l; | |
connect(isL ? r : l, p, isL); connect(p, this, !isL); connect(this, g, isRootP ? false : p == g->l); p->update(); | |
} | |
void Node::splay(Node *rootP) { | |
while (p != rootP) { | |
Node *p = this->p, *g = p->p; | |
if (g != rootP) ((this == p->l) == (p == g->l) ? p : this)->rotate(rootP); | |
rotate(rootP); | |
} | |
update(); | |
} | |
Node T[int(6e5 + 5)], *root = nullptr; int cur = 0; | |
Node *select(Node *x, int k) { | |
if (!x) return nullptr; | |
int t = Size(x->l); | |
if (t > k) return select(x->l, k); | |
else if (t < k) return select(x->r, k - t - 1); | |
return x; | |
} | |
int select(int k) { return select(root, k)->val; } | |
Node *last = nullptr; | |
Node *get(Node *x, int val) { | |
if (!x) return nullptr; | |
last = x; | |
if (val < x->val) return get(x->l, val); | |
else if (val > x->val) return get(x->r, val); | |
return x; | |
} | |
Node *get(int val) { | |
last = nullptr; Node *x = get(root, val); | |
if (last) (root = last)->splay(nullptr); | |
return x; | |
} | |
Node *getMin(Node *x) { return x->l ? getMin(x->l) : x; } | |
int getRank(Node *x, int val) { | |
if (!x) return 0; | |
if (x->val >= val) return getRank(x->l, val); | |
else return 1 + Size(x->l) + getRank(x->r, val); | |
} | |
int getRank(int val) { | |
Node *x = get(val); | |
if (!x) return -1; | |
(root = x)->splay(nullptr); | |
return getRank(root, val); | |
} | |
Node *build(int l, int r, vector<int> &A) { | |
if (l > r) return nullptr; | |
int m = l + (r - l) / 2, i = cur; T[cur++] = Node(A[m]); | |
Node *left = build(l, m - 1, A), *right = build(m + 1, r, A), *x = &(T[i]); | |
connect(left, x, true); connect(right, x, false); x->update(); | |
return x; | |
} | |
void build(vector<int> &A) { root = build(0, int(A.size()) - 1, A); } | |
Node *add(Node *x, int val) { | |
if (!x) { return &(T[cur++] = Node(val)); } | |
if (val < x->val) connect(add(x->l, val), x, true); | |
else connect(add(x->r, val), x, false); | |
x->update(); return x; | |
} | |
void add(int val) { root = add(root, val); T[cur - 1].splay(nullptr); root = &(T[cur - 1]); } | |
void remove(int val) { | |
Node *x = get(val); | |
if (!x) return; | |
x->splay(nullptr); | |
if (!x->l) root = x->r; | |
else if (!x->r) root = x->l; | |
else { getMin(x->r)->splay(x); connect(x->l, root = x->r, true); } | |
connect(root, nullptr, true); | |
} | |
void values(Node *x, vector<int> &A) { | |
if (x) { values(x->l, A); A.push_back(x->val); values(x->r, A); } | |
} | |
void values(vector<int> &A) { values(root, A); } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
#include <ext/pb_ds/assoc_container.hpp> | |
#include <ext/pb_ds/tree_policy.hpp> | |
#include <ext/pb_ds/priority_queue.hpp> | |
using namespace std;using namespace std::placeholders;using namespace __gnu_pbds; | |
#define pb push_back | |
#define eb emplace_back | |
#define mp make_pair | |
#define f first | |
#define s second | |
#define all(a) (a).begin(),(a).end() | |
#define For(i,a,b) for(auto i=(a);i<(b);i++) | |
#define FOR(i,b) For(i,0,b) | |
#define Rev(i,a,b) for(auto i=(a);i>(b);i--) | |
#define REV(i,a) Rev(i,a,-1) | |
#define FORE(i,a) for(auto&&i:a) | |
template<class C>constexpr int sz(const C&c){return int(c.size());} | |
using ll=long long;using ld=long double;using uint=unsigned int;using ull=unsigned long long; | |
using pii=pair<int,int>;using pll=pair<ll,ll>;using pill=pair<int,ll>;using plli=pair<ll,int>;using pdd=pair<double,double>;using pld=pair<ld,ld>; | |
constexpr const char nl='\n',sp=' ';constexpr const int INT_INF=0x3f3f3f3f;constexpr const ll LL_INF=0x3f3f3f3f3f3f3f3f; | |
constexpr const double D_INF=numeric_limits<double>::infinity();constexpr const ld LD_INF=numeric_limits<ld>::infinity(); | |
template<class T>constexpr const T&_min(const T&x,const T&y){return x<y?x:y;}template<class T>constexpr const T&_max(const T&x,const T&y){return x<y?y:x;} | |
template<class T,class...Ts>constexpr const T&_min(const T&x,const Ts&...xs){return _min(x,_min(xs...));} | |
template<class T,class...Ts>constexpr const T&_max(const T&x,const Ts&...xs){return _max(x,_max(xs...));} | |
template<class T,class...Ts>void MIN(T&x,const Ts&...xs){x=_min(x,xs...);}template<class T,class...Ts>void MAX(T&x,const Ts&...xs){x=_max(x,xs...);} | |
template<class T>constexpr const T&_clamp(const T&v,const T&lo,const T&hi){return v<lo?lo:hi<v?hi:v;}template<class T>void CLAMP(T&v,const T&lo,const T&hi){v=_clamp(v,lo,hi);} | |
template<class T,class...Args>unique_ptr<T>_make_unique(Args&&...args){return unique_ptr<T>(new T(forward<Args>(args)...));} | |
template<class T,class...Args>shared_ptr<T>_make_shared(Args&&...args){return shared_ptr<T>(new T(forward<Args>(args)...));} | |
#define min(...) _min(__VA_ARGS__) | |
#define max(...) _max(__VA_ARGS__) | |
#define clamp(...) _clamp(__VA_ARGS__) | |
#define make_unique _make_unique | |
#define make_shared _make_shared | |
seed_seq seq { | |
(uint64_t)chrono::duration_cast<chrono::nanoseconds>(chrono::high_resolution_clock::now().time_since_epoch()).count(), | |
(uint64_t)__builtin_ia32_rdtsc(),(uint64_t)(uintptr_t)make_unique<char>().get() | |
}; | |
mt19937 rng(seq);mt19937_64 rng64(seq);const size_t RANDOM=uniform_int_distribution<size_t>(0,(numeric_limits<size_t>::max)())(rng64); | |
template<class T,class H=hash<T>>struct rand_hash{ | |
static uint64_t splitmix64(uint64_t x){x+=0x9e3779b97f4a7c15;x=(x^(x>>30))*0xbf58476d1ce4e5b9;x=(x^(x>>27))*0x94d049bb133111eb;return x^(x>>31);} | |
size_t operator()(const T&x)const{return splitmix64(H{}(x)+RANDOM);} | |
}; | |
template<class K,class H=rand_hash<K>,class...Ts>using hashset=gp_hash_table<K,null_type,H,Ts...>; | |
template<class K,class V,class H=rand_hash<K>,class...Ts>using hashmap=gp_hash_table<K,V,H,Ts...>; | |
template<class K,class C=less<K>,class...Ts>using treeset=tree<K,null_type,C,rb_tree_tag,tree_order_statistics_node_update,Ts...>; | |
template<class K,class V,class C=less<K>,class...Ts>using treemap=tree<K,V,C,rb_tree_tag,tree_order_statistics_node_update,Ts...>; | |
template<class K,class H=rand_hash<K>,class...Ts>using uset=unordered_set<K,H,Ts...>;template<class K,class V,class H=rand_hash<K>,class...Ts>using umap=unordered_map<K,V,H,Ts...>; | |
template<class T>using minpq=std::priority_queue<T,vector<T>,greater<T>>;template<class T>using maxpq=std::priority_queue<T,vector<T>,less<T>>; | |
template<class T>using minpairingheap=__gnu_pbds::priority_queue<T,greater<T>,pairing_heap_tag>;template<class T>using maxpairingheap=__gnu_pbds::priority_queue<T,less<T>,pairing_heap_tag>; | |
template<class T1,class T2,class H1=rand_hash<T1>,class H2=rand_hash<T2>>struct pair_hash{size_t operator()(const pair<T1,T2>&p)const{return 31*H1{}(p.first)+H2{}(p.second);}}; | |
template<class T>struct is_iterator { | |
template<class U,typename enable_if<!is_convertible<U,const char*>::value,int>::type=0>constexpr static auto has_indirection(int)->decltype(*declval<U>(),bool()){return true;} | |
template<class>constexpr static bool has_indirection(long){return false;}constexpr static bool value=has_indirection<T>(0); | |
}; | |
#define INTERACTIVE_INPUT 0 | |
constexpr const int _bufferSize=1<<16,_maxNumLength=128; | |
char _inputBuffer[_bufferSize+1],*_inputPtr=_inputBuffer,_outputBuffer[_bufferSize],_c,_sign,*_tempInputBuf=nullptr,_numBuf[_maxNumLength],_tempOutputBuf[_maxNumLength],_fill=' '; | |
FILE*_input=stdin,*_output=stdout,*_error=stderr;const char*_delimiter=" ";int _cur,_outputPtr=0,_numPtr=0,_precision=6,_width=0,_tempOutputPtr=0,_cnt;ull _precisionBase=1000000; | |
#ifdef _WIN32 | |
#define getchar_unlocked getchar | |
#define fread_unlocked fread | |
#define fwrite_unlocked fwrite | |
#endif | |
#if INTERACTIVE_INPUT | |
#define _getchar() getchar_unlocked() | |
#else | |
#define _peekchar() (*_inputPtr?*_inputPtr:(_inputBuffer[fread_unlocked(_inputPtr=_inputBuffer,1,_bufferSize,_input)]='\0',*_inputPtr)) | |
#define _getchar() (*_inputPtr?*_inputPtr++:(_inputBuffer[fread_unlocked(_inputPtr=_inputBuffer,1,_bufferSize,_input)]='\0',*_inputPtr++)) | |
#define _hasNext() (*_inputPtr||!feof(_input)) | |
bool hasNext(){while(_hasNext()&&_peekchar()<=' ')_getchar();return _hasNext();}bool hasNextLine(){while(_hasNext()&&_peekchar()=='\r')_getchar();return _hasNext();} | |
#endif | |
#define _readSignAndNum(x) while(((x)=_getchar())<=' ');_sign=(x)=='-';if(_sign)(x)=_getchar();for((x)-='0';(_c=_getchar())>='0';(x)=(x)*10+_c-'0') | |
#define _readFloatingPoint(x,T) for(T _div=1.0;(_c=_getchar())>='0';(x)+=(_c-'0')/(_div*=10)) | |
#define rc(x) do{while(((x)=_getchar())<=' ');}while(0) | |
#define ri(x) do{_readSignAndNum(x);if(_sign)(x)=-(x);}while(0) | |
#define rd(x) do{_readSignAndNum(x);if(_c=='.')_readFloatingPoint(x,double);if(_sign)(x)=-(x);}while(0) | |
#define rld(x) do{_readSignAndNum(x);if(_c=='.')_readFloatingPoint(x,ld);if(_sign)(x)=-(x);}while(0) | |
#define rcs(x) do{_cur=0;do{_c=_getchar();}while(_c<=' ');do{(x)[_cur++]=_c;}while((_c=_getchar())>' ');(x)[_cur]='\0';}while(0) | |
#define rs(x) do{if(!_tempInputBuf)assert(0);rcs(_tempInputBuf);(x)=string(_tempInputBuf,_cur);}while(0) | |
#define rcln(x) do{while(_inputPtr!=_inputBuffer&&*(_inputPtr-1)=='\r')_getchar();_cur=0;while((_c=_getchar())!='\n'&&_c){if(_c!='\r')(x)[_cur++]=_c;}(x)[_cur]='\0';}while(0) | |
#define rln(x) do{if(!_tempInputBuf)assert(0);rcln(_tempInputBuf);(x)=string(_tempInputBuf,_cur);}while(0) | |
void setLength(int x){if(_tempInputBuf)delete[](_tempInputBuf);_tempInputBuf=new char[x+1];} | |
void read(int&x){ri(x);}void read(uint&x){ri(x);}void read(ll&x){ri(x);}void read(ull&x){ri(x);}void read(double&x){rd(x);}void read(ld&x){rld(x);} | |
void read(char&x){rc(x);}void read(char*x){rcs(x);}void read(string&x){rs(x);}void readln(char*x){rcln(x);}void readln(string&x){rln(x);} | |
template<class T1,class T2>void read(pair<T1,T2>&x){read(x.first);read(x.second);}template<class T>void read(complex<T>&x){T _re,_im;read(_re);read(_im);x.real(_re);x.imag(_im);} | |
template<class T>void read(T&x);template<class T,class...Ts>void read(T&x,Ts&&...xs); | |
template<class It>typename enable_if<is_iterator<It>::value>::type read(It st,It en){for(It _i=st;_i!=en;_i++)read(*_i);} | |
template<class It,class...Ts>typename enable_if<is_iterator<It>::value>::type read(It st,It en,Ts&&...xs){read(st,en);read(forward<Ts>(xs)...);} | |
template<class T>void read(T&x){for(auto&&_i:x)read(_i);}template<class T,class...Ts>void read(T&x,Ts&&...xs){read(x);read(forward<Ts>(xs)...);} | |
void setInput(FILE*file){*_inputPtr='\0';_input=file;}void setInput(const char*s){*_inputPtr='\0';_input=fopen(s,"r");}void setInput(const string&s){*_inputPtr='\0';_input=fopen(s.c_str(),"r");} | |
#define _flush() do{_flushBuf();fflush(_output);}while(0) | |
#define _flushBuf() (fwrite_unlocked(_outputBuffer,1,_outputPtr,_output),_outputPtr=0) | |
#define _putchar(x) (_outputBuffer[_outputPtr==_bufferSize?_flushBuf():_outputPtr]=(x),_outputPtr++) | |
#define _writeTempBuf(x) (_tempOutputBuf[_tempOutputPtr++]=(x)) | |
#define _writeOutput() for(int _i=0;_i<_tempOutputPtr;_putchar(_tempOutputBuf[_i++]));_tempOutputPtr=0 | |
#define _writeNum(x,T,digits) _cnt=0;for(T _y=(x);_y;_y/=10,_cnt++)_numBuf[_numPtr++]='0'+_y%10;for(;_cnt<digits;_cnt++)_numBuf[_numPtr++]='0';_flushNumBuf(); | |
#define _writeFloatingPoint(x,T) ull _I=(ull)(x);ull _F=((x)-_I)*_precisionBase+(T)(0.5);if(_F>=_precisionBase){_I++;_F=0;}_writeNum(_I,ull,1);_writeTempBuf('.');_writeNum(_F,ull,_precision) | |
#define _checkFinite(x) if(std::isnan(x)){wcs("NaN");}else if(std::isinf(x)){wcs("Inf");} | |
#define _flushNumBuf() for(;_numPtr;_writeTempBuf(_numBuf[--_numPtr])) | |
#define _fillBuf(x) for(int _i=0;_i<(x);_i++)_putchar(_fill) | |
#define _flushTempBuf() int _tempLen=_tempOutputPtr;_fillBuf(_width-_tempLen);_writeOutput();_fillBuf(-_width-_tempLen) | |
#define wb(x) do{if(x)_writeTempBuf('1');else _writeTempBuf('0');_flushTempBuf();}while(0) | |
#define wc(x) do{_writeTempBuf(x); _flushTempBuf();}while(0) | |
#define wi(x) do{if((x)<0){_writeTempBuf('-');_writeNum(-(x),uint,1);}else{_writeNum(x,uint,1);}_flushTempBuf();}while(0) | |
#define wll(x) do{if((x)<0){_writeTempBuf('-');_writeNum(-(x),ull,1);}else{_writeNum(x,ull,1);}_flushTempBuf();}while(0) | |
#define wd(x) do{_checkFinite(x)else if((x)<0){_writeTempBuf('-');_writeFloatingPoint(-(x),double);}else{_writeFloatingPoint(x,double);}_flushTempBuf();}while(0) | |
#define wld(x) do{_checkFinite(x)else if((x)<0){_writeTempBuf('-');_writeFloatingPoint(-(x),ld);}else{_writeFloatingPoint(x,ld);}_flushTempBuf();}while(0) | |
#define wcs(x) do{int _slen=strlen(x);_fillBuf(_width-_slen);for(const char*_p=(x);*_p;_putchar(*_p++));_fillBuf(-_width-_slen);}while(0) | |
#define ws(x) do{_fillBuf(_width-int((x).length()));for(int _i=0;_i<int((x).length());_putchar(x[_i++]));_fillBuf(-_width-int((x).length()));}while(0) | |
void setPrecision(int x){_precision=x;_precisionBase=1;for(int _i=0;_i<x;_i++,_precisionBase*=10);}void setWidth(int x){_width=x;}void setFill(char x){_fill=x;} | |
void setDelimiter(const char*x){_delimiter=x;}void setDelimiter(const string&x){_delimiter=x.c_str();} | |
void writeDelimiter(){for(const char*_p=_delimiter;*_p;_putchar(*_p++));} | |
void write(const bool&x){wb(x);}void write(const int&x){wi(x);}void write(const uint&x){wi(x);}void write(const ll&x){wll(x);}void write(const ull&x){wll(x);} | |
void write(const double&x){wd(x);}void write(const ld&x){wld(x);}void write(const char&x){wc(x);}void write(const char*x){wcs(x);}void write(const string&x){ws(x);} | |
template<class T1,class T2>void write(const pair<T1,T2>&x){write(x.first);writeDelimiter();write(x.second);} | |
template<class T>void write(const complex<T>&x){write(x.real());writeDelimiter();write(x.imag());} | |
template<class T>void write(const T&x);template<class T,class...Ts>void write(const T&x,Ts&&...xs); | |
template<class It>typename enable_if<is_iterator<It>::value>::type write(It st,It en){bool _first=1;for(It _i=st;_i!=en;_i++){if(_first)_first=0;else writeDelimiter();write(*_i);}} | |
template<class It,class...Ts>typename enable_if<is_iterator<It>::value>::type write(It st,It en,Ts&&...xs){write(st,en);writeDelimiter();write(forward<Ts>(xs)...);} | |
template<class T>void write(const T&x){bool _first=1;for(auto&&_i:x){if(_first)_first=0;else writeDelimiter();write(_i);}} | |
template<class T,class...Ts>void write(const T&x,Ts&&...xs){write(x);writeDelimiter();write(forward<Ts>(xs)...);} | |
void writeln(){_putchar('\n');}template<class...Ts>void writeln(Ts&&...xs){write(forward<Ts>(xs)...);_putchar('\n');} | |
void flush(){_flush();}class IOManager{public:~IOManager(){flush();if(_tempInputBuf)delete[](_tempInputBuf);}};unique_ptr<IOManager>iomanager=make_unique<IOManager>(); | |
void setOutput(FILE*file){flush();_output=file;}void setOutput(const char*s){flush();_output=fopen(s,"w");}void setOutput(const string&s){flush();_output=fopen(s.c_str(),"w");} | |
template<class...Ts>void debug(const Ts&...xs){FILE*_temp=_output;setOutput(_error);write(xs...);setOutput(_temp);} | |
template<class...Ts>void debugln(const Ts&...xs){FILE*_temp=_output;setOutput(_error);writeln(xs...);setOutput(_temp);} | |
void setError(FILE*file){flush();_error=file;}void setError(const char*s){flush();_error=fopen(s,"w");}void setError(const string&s){flush();_error=fopen(s.c_str(),"w");} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment