This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub maspypy/library
#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() { 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 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; } };