This documentation is automatically generated by online-judge-tools/verification-helper
#include "graph/ds/range_edge_connected_component_query.hpp"
#include "graph/ds/link_cut_tree.hpp"
#include "graph/ds/lct_node_commutative_monoid.hpp"
#include "alg/monoid/min.hpp"
#include "graph/base.hpp"
#include "ds/fenwicktree/fenwicktree_01.hpp"
// https://codeforces.com/problemset/problem/1386/C (TLE)
// query(L,R) = # of component if edge L,...,R-1 are used.
struct Range_Edge_Conneced_Component_Query {
Graph<int, 0>& G;
vc<pair<int, int>> query;
Range_Edge_Conneced_Component_Query(Graph<int, 0>& G) : G(G) {}
void add_query(int l, int r) { query.eb(l, r); }
using Mono = Monoid_Min<int>;
using Node = LCT_Node_Commutative_Monoid<Mono>;
vc<int> calc() {
int N = G.N, M = G.M;
Link_Cut_Tree<Node> LCT(N + M);
int Q = len(query);
vc<int> ANS(Q);
vvc<int> QID(M);
FOR(q, Q) {
auto [l, r] = query[q];
assert(0 <= l && l <= r && r <= M);
if (r) QID[r - 1].eb(q);
}
FenwickTree_01 bit(M);
FOR(i, M) {
int a = G.edges[i].frm, b = G.edges[i].to;
if (a != b && LCT.get_root(a) == LCT.get_root(b)) {
int k = LCT.prod_path(a, b);
int c = G.edges[k].frm, d = G.edges[k].to;
bit.add(k, -1);
LCT.cut(c, N + k), LCT.cut(d, N + k);
}
if (a != b) {
LCT.set(N + i, i);
LCT.link(a, N + i), LCT.link(b, N + i);
bit.add(i, 1);
}
for (auto& q: QID[i]) {
auto [l, r] = query[q];
ANS[q] = N - bit.sum(l, r);
}
}
return ANS;
}
};
#line 1 "graph/ds/range_edge_connected_component_query.hpp"
#line 1 "graph/ds/link_cut_tree.hpp"
/*
各 heavy path を head が左, tail が右となるように splay tree で持つ.
ユーザーが直接呼ぶ可能性があるものだけ int でも実装.
LCT 外で探索するときなど,push を忘れないように注意.
*/
template <typename Node>
struct Link_Cut_Tree {
using np = Node *;
int n;
vc<Node> nodes;
Link_Cut_Tree(int n = 0) : n(n), nodes(n) { FOR(i, n) nodes[i] = Node(i); }
Node *operator[](int v) { return &nodes[v]; }
// underlying tree の根
Node *get_root(Node *c) {
expose(c);
c->push();
while (c->l) {
c = c->l;
c->push();
}
splay(c);
return c;
}
// underlying tree の根
int get_root(int c) { return get_root(&nodes[c])->idx; }
// parent(c)==p となるように link.
void link(Node *c, Node *p) {
evert(c);
expose(p);
p->push();
// no edge -> heavy edge
assert(!(c->p));
assert(!(p->r));
c->p = p;
p->r = c;
p->update();
}
// parent(c)==p となるように link.
void link(int c, int p) { return link(&nodes[c], &nodes[p]); }
void cut(Node *a, Node *b) {
evert(a);
expose(b);
assert(!b->p);
assert((b->l) == a);
// heavy edge -> no edge
b->l->p = nullptr;
b->l = nullptr;
b->update();
}
void cut(int a, int b) { return cut(&nodes[a], &nodes[b]); }
// c を underlying tree の根とする.
// c は splay tree の根にもなる.
// c は push 済になる
void evert(Node *c) {
expose(c);
c->reverse();
c->push();
}
// c を underlying tree の根とする.
// c は splay tree の根にもなる.
void evert(int c) { evert(&nodes[c]); }
Node *lca(Node *u, Node *v) {
assert(get_root(u) == get_root(v));
expose(u);
return expose(v);
}
int lca(int u, int v) { return lca(&nodes[u], &nodes[v])->idx; }
// 辺の個数
int dist(int u, int v) {
evert(u), expose(v);
return ((*this)[v]->size) - 1;
}
Node *jump(Node *u, Node *v, int k) {
evert(v);
expose(u);
assert(0 <= k && k < (u->size));
while (1) {
u->push();
int rs = (u->r ? u->r->size : 0);
if (k < rs) {
u = u->r;
continue;
}
if (k == rs) { break; }
k -= rs + 1;
u = u->l;
}
splay(u);
return u;
}
int jump(int u, int v, int k) {
auto c = jump((*this)[u], (*this)[v], k);
return c->idx;
}
// [root, c] がひとつの splay tree になるように変更する.
// c が右端で splay tree の根という状態になる.
// path query はこの状態で c の data を見る.
// c は push 済になる
virtual Node *expose(Node *c) {
Node *now = c;
Node *rp = nullptr; // 今まで作ったパス
while (now) {
splay(now);
// heavy -> light, light -> heavy.
if (now->r) { now->add_light(now->r); }
if (rp) { now->erase_light(rp); }
now->r = rp;
now->update();
rp = now;
now = now->p;
}
splay(c);
return rp;
}
// [root, c] がひとつの splay tree になるように変更する.
// c が右端で splay tree の根という状態になる.
// path query はこの状態で c の data を見る.
int expose(int c) {
Node *x = expose(&nodes[c]);
if (!x) return -1;
return x->idx;
}
Node *get_parent(Node *x) {
expose(x);
x->push();
if (!x->l) return nullptr;
x = x->l, x->push();
while (x->r) x = x->r, x->push();
return x;
}
int get_parent(int x) {
Node *p = get_parent((*this)[x]);
return (p ? p->idx : -1);
}
void set(Node *c, typename Node::VX x) {
evert(c);
c->set(x);
}
void set(int c, typename Node::VX x) { set((*this)[c], x); }
typename Node::X prod_path(int a, int b) {
evert(a), expose(b);
return (*this)[b]->x;
}
// subtree 用の node を使う
typename Node::X prod_subtree(int v, int root) {
static_assert(Node::NODE_FOR_SUBTREE);
if (v == root) {
evert(root);
return (*this)[root]->x;
}
root = jump(v, root, 1);
cut(v, root);
typename Node::X res = (*this)[v]->x;
link(v, root);
return res;
}
vc<int> collect_heavy_path(int v) {
np c = (*this)[v];
while (!is_root(c)) c = c->p;
vc<int> res;
auto dfs = [&](auto &dfs, np c, bool rev) -> void {
if (!rev) {
if (c->l) dfs(dfs, c->l, rev ^ c->rev);
res.eb(c->idx);
if (c->r) dfs(dfs, c->r, rev ^ c->rev);
} else {
if (c->r) dfs(dfs, c->r, rev ^ c->rev);
res.eb(c->idx);
if (c->l) dfs(dfs, c->l, rev ^ c->rev);
}
};
dfs(dfs, c, false);
return res;
}
void debug() {
print("p, l, r, rev");
auto f = [&](np c) -> int { return (c ? c->idx : -1); };
FOR(i, len(nodes)) { print(i, ",", f((*this)[i]->p), f((*this)[i]->l), f((*this)[i]->r), (*this)[i]->rev); }
FOR(i, len(nodes)) {
np c = (*this)[i];
if (c->l) assert(c->l->p == c);
if (c->r) assert(c->r->p == c);
}
}
private:
// splay tree 内で完結する操作. 特に heavy, light 構造は変わらない.
// light pointer は rotate 内でケア
// c は push 済になる
void splay(Node *c) {
c->push();
while (!is_root(c)) {
Node *p = c->p;
Node *pp = (p ? p->p : nullptr);
if (state(p) == 0) {
p->push(), c->push();
rotate(c);
}
elif (state(c) == state(p)) {
pp->push(), p->push(), c->push();
rotate(p);
rotate(c);
}
else {
pp->push(), p->push(), c->push();
rotate(c);
rotate(c);
}
}
}
// パスを表す splay tree の根になっているかどうか
// underlying tree ではない
bool is_root(Node *c) { return state(c) == 0; }
// splay tree 内で完結する操作. 特に heavy, light 構造は変わらない.
// light edge のポインタは変更されうる
void rotate(Node *n) {
// n を根に近づける
Node *pp, *p, *c;
p = n->p;
pp = p->p;
if (p->l == n) {
c = n->r;
n->r = p;
p->l = c;
} else {
c = n->l;
n->l = p;
p->r = c;
}
p->update(), n->update();
if (pp) {
if (pp->l == p) pp->l = n;
elif (pp->r == p) pp->r = n;
else {
// light edge pointer が (pp-p) から (pp-n) に変わる
pp->change_light(p, n);
}
}
n->p = pp;
p->p = n;
if (c) c->p = p;
}
inline int state(Node *n) {
if (!n->p) return 0;
if (n->p->l == n) return 1;
if (n->p->r == n) return -1;
return 0;
}
};
#line 1 "graph/ds/lct_node_commutative_monoid.hpp"
// SUBTREE : cluster が subtree 情報を持つ場合
template <typename Monoid, bool SUBTREE = false>
struct LCT_Node_Commutative_Monoid {
static_assert(Monoid::commute);
static constexpr bool NODE_FOR_SUBTREE = SUBTREE;
using np = LCT_Node_Commutative_Monoid *;
// デフォルト
np l, r, p;
int idx, size; // size は heavy path の頂点数
bool rev;
// 目的ごとに定義する.
using MX = Monoid;
using X = typename MX::value_type;
using VX = X;
X x, vx, mid;
LCT_Node_Commutative_Monoid(int i = 0)
: l(nullptr),
r(nullptr),
p(nullptr),
idx(i),
size(1),
rev(0),
x(MX::unit()),
vx(MX::unit()),
mid(MX::unit()) {}
void update() {
size = 1;
x = vx;
if constexpr (SUBTREE) x = MX::op(x, mid);
if (l) { size += l->size, x = Monoid::op(l->x, x); }
if (r) { size += r->size, x = Monoid::op(x, r->x); }
}
void push() {
if (rev) {
if (l) l->reverse();
if (r) r->reverse();
rev = 0;
}
}
// data の reverse も行う
void reverse() {
rev ^= 1;
swap(l, r);
}
// LCT 内で expose, update を行うのでここは変更だけ
void set(VX x) { vx = x; }
void add_light(np c) {
if constexpr (SUBTREE) mid = MX::op(mid, c->x);
}
void erase_light(np c) {
if constexpr (SUBTREE) mid = MX::op(mid, MX::inverse(c->x));
}
// b->x に subtree value が入っている.
void change_light(np a, np b) {}
};
#line 2 "alg/monoid/min.hpp"
template <typename E>
struct Monoid_Min {
using X = E;
using value_type = X;
static constexpr X op(const X &x, const X &y) noexcept { return min(x, y); }
static constexpr X unit() { return infty<E>; }
static constexpr bool commute = true;
};
#line 2 "ds/hashmap.hpp"
// u64 -> Val
template <typename Val>
struct HashMap {
// n は入れたいものの個数で ok
HashMap(u32 n = 0) { build(n); }
void build(u32 n) {
u32 k = 8;
while (k < n * 2) k *= 2;
cap = k / 2, mask = k - 1;
key.resize(k), val.resize(k), used.assign(k, 0);
}
// size を保ったまま. size=0 にするときは build すること.
void clear() {
used.assign(len(used), 0);
cap = (mask + 1) / 2;
}
int size() { return len(used) / 2 - cap; }
int index(const u64& k) {
int i = 0;
for (i = hash(k); used[i] && key[i] != k; i = (i + 1) & mask) {}
return i;
}
Val& operator[](const u64& k) {
if (cap == 0) extend();
int i = index(k);
if (!used[i]) { used[i] = 1, key[i] = k, val[i] = Val{}, --cap; }
return val[i];
}
Val get(const u64& k, Val default_value) {
int i = index(k);
return (used[i] ? val[i] : default_value);
}
bool count(const u64& k) {
int i = index(k);
return used[i] && key[i] == k;
}
// f(key, val)
template <typename F>
void enumerate_all(F f) {
FOR(i, len(used)) if (used[i]) f(key[i], val[i]);
}
private:
u32 cap, mask;
vc<u64> key;
vc<Val> val;
vc<bool> used;
u64 hash(u64 x) {
static const u64 FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count();
x += FIXED_RANDOM;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return (x ^ (x >> 31)) & mask;
}
void extend() {
vc<pair<u64, Val>> dat;
dat.reserve(len(used) / 2 - cap);
FOR(i, len(used)) {
if (used[i]) dat.eb(key[i], val[i]);
}
build(2 * len(dat));
for (auto& [a, b]: dat) (*this)[a] = b;
}
};
#line 3 "graph/base.hpp"
template <typename T>
struct Edge {
int frm, to;
T cost;
int id;
};
template <typename T = int, bool directed = false>
struct Graph {
static constexpr bool is_directed = directed;
int N, M;
using cost_type = T;
using edge_type = Edge<T>;
vector<edge_type> edges;
vector<int> indptr;
vector<edge_type> csr_edges;
vc<int> vc_deg, vc_indeg, vc_outdeg;
bool prepared;
class OutgoingEdges {
public:
OutgoingEdges(const Graph* G, int l, int r) : G(G), l(l), r(r) {}
const edge_type* begin() const {
if (l == r) { return 0; }
return &G->csr_edges[l];
}
const edge_type* end() const {
if (l == r) { return 0; }
return &G->csr_edges[r];
}
private:
const Graph* G;
int l, r;
};
bool is_prepared() { return prepared; }
Graph() : N(0), M(0), prepared(0) {}
Graph(int N) : N(N), M(0), prepared(0) {}
void build(int n) {
N = n, M = 0;
prepared = 0;
edges.clear();
indptr.clear();
csr_edges.clear();
vc_deg.clear();
vc_indeg.clear();
vc_outdeg.clear();
}
void add(int frm, int to, T cost = 1, int i = -1) {
assert(!prepared);
assert(0 <= frm && 0 <= to && to < N);
if (i == -1) i = M;
auto e = edge_type({frm, to, cost, i});
edges.eb(e);
++M;
}
#ifdef FASTIO
// wt, off
void read_tree(bool wt = false, int off = 1) { read_graph(N - 1, wt, off); }
void read_graph(int M, bool wt = false, int off = 1) {
for (int m = 0; m < M; ++m) {
INT(a, b);
a -= off, b -= off;
if (!wt) {
add(a, b);
} else {
T c;
read(c);
add(a, b, c);
}
}
build();
}
#endif
void build() {
assert(!prepared);
prepared = true;
indptr.assign(N + 1, 0);
for (auto&& e: edges) {
indptr[e.frm + 1]++;
if (!directed) indptr[e.to + 1]++;
}
for (int v = 0; v < N; ++v) { indptr[v + 1] += indptr[v]; }
auto counter = indptr;
csr_edges.resize(indptr.back() + 1);
for (auto&& e: edges) {
csr_edges[counter[e.frm]++] = e;
if (!directed) csr_edges[counter[e.to]++] = edge_type({e.to, e.frm, e.cost, e.id});
}
}
OutgoingEdges operator[](int v) const {
assert(prepared);
return {this, indptr[v], indptr[v + 1]};
}
vc<int> deg_array() {
if (vc_deg.empty()) calc_deg();
return vc_deg;
}
pair<vc<int>, vc<int>> deg_array_inout() {
if (vc_indeg.empty()) calc_deg_inout();
return {vc_indeg, vc_outdeg};
}
int deg(int v) {
if (vc_deg.empty()) calc_deg();
return vc_deg[v];
}
int in_deg(int v) {
if (vc_indeg.empty()) calc_deg_inout();
return vc_indeg[v];
}
int out_deg(int v) {
if (vc_outdeg.empty()) calc_deg_inout();
return vc_outdeg[v];
}
#ifdef FASTIO
void debug() {
#ifdef LOCAL
print("Graph");
if (!prepared) {
print("frm to cost id");
for (auto&& e: edges) print(e.frm, e.to, e.cost, e.id);
} else {
print("indptr", indptr);
print("frm to cost id");
FOR(v, N) for (auto&& e: (*this)[v]) print(e.frm, e.to, e.cost, e.id);
}
#endif
}
#endif
vc<int> new_idx;
vc<bool> used_e;
// G における頂点 V[i] が、新しいグラフで i になるようにする
// {G, es}
// sum(deg(v)) の計算量になっていて、
// 新しいグラフの n+m より大きい可能性があるので注意
Graph<T, directed> rearrange(vc<int> V, bool keep_eid = 0) {
if (len(new_idx) != N) new_idx.assign(N, -1);
int n = len(V);
FOR(i, n) new_idx[V[i]] = i;
Graph<T, directed> G(n);
vc<int> history;
FOR(i, n) {
for (auto&& e: (*this)[V[i]]) {
if (len(used_e) <= e.id) used_e.resize(e.id + 1);
if (used_e[e.id]) continue;
int a = e.frm, b = e.to;
if (new_idx[a] != -1 && new_idx[b] != -1) {
history.eb(e.id);
used_e[e.id] = 1;
int eid = (keep_eid ? e.id : -1);
G.add(new_idx[a], new_idx[b], e.cost, eid);
}
}
}
FOR(i, n) new_idx[V[i]] = -1;
for (auto&& eid: history) used_e[eid] = 0;
G.build();
return G;
}
Graph<T, true> to_directed_tree(int root = -1) {
if (root == -1) root = 0;
assert(!is_directed && prepared && M == N - 1);
Graph<T, true> G1(N);
vc<int> par(N, -1);
auto dfs = [&](auto& dfs, int v) -> void {
for (auto& e: (*this)[v]) {
if (e.to == par[v]) continue;
par[e.to] = v, dfs(dfs, e.to);
}
};
dfs(dfs, root);
for (auto& e: edges) {
int a = e.frm, b = e.to;
if (par[a] == b) swap(a, b);
assert(par[b] == a);
G1.add(a, b, e.cost);
}
G1.build();
return G1;
}
HashMap<int> MP_FOR_EID;
int get_eid(u64 a, u64 b) {
if (len(MP_FOR_EID) == 0) {
MP_FOR_EID.build(N - 1);
for (auto& e: edges) {
u64 a = e.frm, b = e.to;
u64 k = to_eid_key(a, b);
MP_FOR_EID[k] = e.id;
}
}
return MP_FOR_EID.get(to_eid_key(a, b), -1);
}
u64 to_eid_key(u64 a, u64 b) {
if (!directed && a > b) swap(a, b);
return N * a + b;
}
private:
void calc_deg() {
assert(vc_deg.empty());
vc_deg.resize(N);
for (auto&& e: edges) vc_deg[e.frm]++, vc_deg[e.to]++;
}
void calc_deg_inout() {
assert(vc_indeg.empty());
vc_indeg.resize(N);
vc_outdeg.resize(N);
for (auto&& e: edges) { vc_indeg[e.to]++, vc_outdeg[e.frm]++; }
}
};
#line 2 "ds/fenwicktree/fenwicktree_01.hpp"
#line 2 "alg/monoid/add.hpp"
template <typename E>
struct Monoid_Add {
using X = E;
using value_type = X;
static constexpr X op(const X &x, const X &y) noexcept { return x + y; }
static constexpr X inverse(const X &x) noexcept { return -x; }
static constexpr X power(const X &x, ll n) noexcept { return X(n) * x; }
static constexpr X unit() { return X(0); }
static constexpr bool commute = true;
};
#line 3 "ds/fenwicktree/fenwicktree.hpp"
template <typename Monoid>
struct FenwickTree {
using G = Monoid;
using MX = Monoid;
using E = typename G::value_type;
int n;
vector<E> dat;
E total;
FenwickTree() {}
FenwickTree(int n) { build(n); }
template <typename F>
FenwickTree(int n, F f) {
build(n, f);
}
FenwickTree(const vc<E>& v) { build(v); }
void build(int m) {
n = m;
dat.assign(m, G::unit());
total = G::unit();
}
void build(const vc<E>& v) {
build(len(v), [&](int i) -> E { return v[i]; });
}
template <typename F>
void build(int m, F f) {
n = m;
dat.clear();
dat.reserve(n);
total = G::unit();
FOR(i, n) { dat.eb(f(i)); }
for (int i = 1; i <= n; ++i) {
int j = i + (i & -i);
if (j <= n) dat[j - 1] = G::op(dat[i - 1], dat[j - 1]);
}
total = prefix_sum(m);
}
E prod_all() { return total; }
E sum_all() { return total; }
E sum(int k) { return prefix_sum(k); }
E prod(int k) { return prefix_prod(k); }
E prefix_sum(int k) { return prefix_prod(k); }
E prefix_prod(int k) {
chmin(k, n);
E ret = G::unit();
for (; k > 0; k -= k & -k) ret = G::op(ret, dat[k - 1]);
return ret;
}
E sum(int L, int R) { return prod(L, R); }
E prod(int L, int R) {
chmax(L, 0), chmin(R, n);
if (L == 0) return prefix_prod(R);
assert(0 <= L && L <= R && R <= n);
E pos = G::unit(), neg = G::unit();
while (L < R) { pos = G::op(pos, dat[R - 1]), R -= R & -R; }
while (R < L) { neg = G::op(neg, dat[L - 1]), L -= L & -L; }
return G::op(pos, G::inverse(neg));
}
vc<E> get_all() {
vc<E> res(n);
FOR(i, n) res[i] = prod(i, i + 1);
return res;
}
void add(int k, E x) { multiply(k, x); }
void multiply(int k, E x) {
static_assert(G::commute);
total = G::op(total, x);
for (++k; k <= n; k += k & -k) dat[k - 1] = G::op(dat[k - 1], x);
}
void set(int k, E x) { add(k, G::op(G::inverse(prod(k, k + 1)), x)); }
template <class F>
int max_right(const F check, int L = 0) {
assert(check(G::unit()));
E s = G::unit();
int i = L;
// 2^k 進むとダメ
int k = [&]() {
while (1) {
if (i % 2 == 1) { s = G::op(s, G::inverse(dat[i - 1])), i -= 1; }
if (i == 0) { return topbit(n) + 1; }
int k = lowbit(i) - 1;
if (i + (1 << k) > n) return k;
E t = G::op(s, dat[i + (1 << k) - 1]);
if (!check(t)) { return k; }
s = G::op(s, G::inverse(dat[i - 1])), i -= i & -i;
}
}();
while (k) {
--k;
if (i + (1 << k) - 1 < len(dat)) {
E t = G::op(s, dat[i + (1 << k) - 1]);
if (check(t)) { i += (1 << k), s = t; }
}
}
return i;
}
// check(i, x)
template <class F>
int max_right_with_index(const F check, int L = 0) {
assert(check(L, G::unit()));
E s = G::unit();
int i = L;
// 2^k 進むとダメ
int k = [&]() {
while (1) {
if (i % 2 == 1) { s = G::op(s, G::inverse(dat[i - 1])), i -= 1; }
if (i == 0) { return topbit(n) + 1; }
int k = lowbit(i) - 1;
if (i + (1 << k) > n) return k;
E t = G::op(s, dat[i + (1 << k) - 1]);
if (!check(i + (1 << k), t)) { return k; }
s = G::op(s, G::inverse(dat[i - 1])), i -= i & -i;
}
}();
while (k) {
--k;
if (i + (1 << k) - 1 < len(dat)) {
E t = G::op(s, dat[i + (1 << k) - 1]);
if (check(i + (1 << k), t)) { i += (1 << k), s = t; }
}
}
return i;
}
template <class F>
int min_left(const F check, int R) {
assert(check(G::unit()));
E s = G::unit();
int i = R;
// false になるところまで戻る
int k = 0;
while (i > 0 && check(s)) {
s = G::op(s, dat[i - 1]);
k = lowbit(i);
i -= i & -i;
}
if (check(s)) {
assert(i == 0);
return 0;
}
// 2^k 進むと ok になる
// false を維持して進む
while (k) {
--k;
E t = G::op(s, G::inverse(dat[i + (1 << k) - 1]));
if (!check(t)) { i += (1 << k), s = t; }
}
return i + 1;
}
int kth(E k, int L = 0) {
return max_right([&k](E x) -> bool { return x <= k; }, L);
}
};
#line 4 "ds/fenwicktree/fenwicktree_01.hpp"
struct FenwickTree_01 {
int N, n;
vc<u64> dat;
FenwickTree<Monoid_Add<int>> bit;
FenwickTree_01() {}
FenwickTree_01(int n) { build(n); }
template <typename F>
FenwickTree_01(int n, F f) {
build(n, f);
}
void build(int m) {
N = m;
n = ceil<int>(N + 1, 64);
dat.assign(n, u64(0));
bit.build(n);
}
template <typename F>
void build(int m, F f) {
N = m;
n = ceil<int>(N + 1, 64);
dat.assign(n, u64(0));
FOR(i, N) { dat[i / 64] |= u64(f(i)) << (i % 64); }
bit.build(n, [&](int i) -> int { return popcnt(dat[i]); });
}
int sum_all() { return bit.sum_all(); }
int sum(int k) { return prefix_sum(k); }
int prefix_sum(int k) {
int ans = bit.sum(k / 64);
ans += popcnt(dat[k / 64] & ((u64(1) << (k % 64)) - 1));
return ans;
}
int sum(int L, int R) {
if (L == 0) return prefix_sum(R);
int ans = 0;
ans -= popcnt(dat[L / 64] & ((u64(1) << (L % 64)) - 1));
ans += popcnt(dat[R / 64] & ((u64(1) << (R % 64)) - 1));
ans += bit.sum(L / 64, R / 64);
return ans;
}
void add(int k, int x) {
if (x == 1) add(k);
elif (x == -1) remove(k);
else assert(0);
}
void add(int k) {
dat[k / 64] |= u64(1) << (k % 64);
bit.add(k / 64, 1);
}
void remove(int k) {
dat[k / 64] &= ~(u64(1) << (k % 64));
bit.add(k / 64, -1);
}
int kth(int k, int L = 0) {
if (k >= sum_all()) return N;
k += popcnt(dat[L / 64] & ((u64(1) << (L % 64)) - 1));
L /= 64;
int mid = 0;
auto check = [&](auto e) -> bool {
if (e <= k) chmax(mid, e);
return e <= k;
};
int idx = bit.max_right(check, L);
if (idx == n) return N;
k -= mid;
u64 x = dat[idx];
int p = popcnt(x);
if (p <= k) return N;
k = binary_search([&](int n) -> bool { return (p - popcnt(x >> n)) <= k; }, 0, 64, 0);
return 64 * idx + k;
}
int next(int k) {
int idx = k / 64;
k %= 64;
u64 x = dat[idx] & ~((u64(1) << k) - 1);
if (x) return 64 * idx + lowbit(x);
idx = bit.kth(0, idx + 1);
if (idx == n || !dat[idx]) return N;
return 64 * idx + lowbit(dat[idx]);
}
int prev(int k) {
if (k == N) --k;
int idx = k / 64;
k %= 64;
u64 x = dat[idx];
if (k < 63) x &= (u64(1) << (k + 1)) - 1;
if (x) return 64 * idx + topbit(x);
idx = bit.min_left([&](auto e) -> bool { return e <= 0; }, idx) - 1;
if (idx == -1) return -1;
return 64 * idx + topbit(dat[idx]);
}
};
#line 7 "graph/ds/range_edge_connected_component_query.hpp"
// https://codeforces.com/problemset/problem/1386/C (TLE)
// query(L,R) = # of component if edge L,...,R-1 are used.
struct Range_Edge_Conneced_Component_Query {
Graph<int, 0>& G;
vc<pair<int, int>> query;
Range_Edge_Conneced_Component_Query(Graph<int, 0>& G) : G(G) {}
void add_query(int l, int r) { query.eb(l, r); }
using Mono = Monoid_Min<int>;
using Node = LCT_Node_Commutative_Monoid<Mono>;
vc<int> calc() {
int N = G.N, M = G.M;
Link_Cut_Tree<Node> LCT(N + M);
int Q = len(query);
vc<int> ANS(Q);
vvc<int> QID(M);
FOR(q, Q) {
auto [l, r] = query[q];
assert(0 <= l && l <= r && r <= M);
if (r) QID[r - 1].eb(q);
}
FenwickTree_01 bit(M);
FOR(i, M) {
int a = G.edges[i].frm, b = G.edges[i].to;
if (a != b && LCT.get_root(a) == LCT.get_root(b)) {
int k = LCT.prod_path(a, b);
int c = G.edges[k].frm, d = G.edges[k].to;
bit.add(k, -1);
LCT.cut(c, N + k), LCT.cut(d, N + k);
}
if (a != b) {
LCT.set(N + i, i);
LCT.link(a, N + i), LCT.link(b, N + i);
bit.add(i, 1);
}
for (auto& q: QID[i]) {
auto [l, r] = query[q];
ANS[q] = N - bit.sum(l, r);
}
}
return ANS;
}
};