#include "bits/stdc++.h" // Tomasz Nowak using namespace std; // Poland using LL = long long; #define FOR(i, l, r) for(int i = (l); i <= (r); ++i) #define REP(i, n) FOR(i, 0, (n) - 1) template int ssize(T &&x) { return int(x.size()); } template ostream& operator<<(ostream &out, const pair &p) { return out << '(' << p.first << ", " << p.second << ')'; } template auto operator<<(ostream &out, T &&x) -> decltype(x.begin(), out) { out << '{'; for(auto it = x.begin(); it != x.end(); ++it) out << *it << (it == prev(x.end()) ? "" : ", "); return out << '}'; } void dump() {} template void dump(T &&x, Args... args) { cerr << x << "; "; dump(args...); } #ifdef DEBUG struct Nl{~Nl(){cerr << '\n';}}; # define debug(x...) cerr << (strcmp(#x, "") ? #x ": " : ""), dump(x), Nl(), cerr << "" #else # define debug(...) 0 && cerr #endif mt19937_64 rng(0); int rd(int l, int r) { return uniform_int_distribution(l, r)(rng); } // end of templates /** * Author: Simon Lindholm * Date: 2016-07-25 * Source: https://github.com/ngthanhtrung23/ACM_Notebook_new/blob/master/DataStructure/LinkCut.h * Description: Represents a forest of unrooted trees. You can add and remove * edges (as long as the result is still a forest), and check whether * two nodes are in the same tree. * Time: All operations take amortized O(\log N). * Status: Stress-tested a bit for N <= 20 */ struct Node { // Splay tree. Root's pp contains tree's parent. Node *p = 0, *pp = 0, *c[2]; bool flip = 0; Node() { c[0] = c[1] = 0; fix(); } void fix() { if (c[0]) c[0]->p = this; if (c[1]) c[1]->p = this; // (+ update sum of subtree elements etc. if wanted) } void pushFlip() { if (!flip) return; flip = 0; swap(c[0], c[1]); if (c[0]) c[0]->flip ^= 1; if (c[1]) c[1]->flip ^= 1; } int up() { return p ? p->c[1] == this : -1; } void rot(int i, int b) { int h = i ^ b; Node *x = c[i], *y = b == 2 ? x : x->c[h], *z = b ? y : x; if ((y->p = p)) p->c[up()] = y; c[i] = z->c[i ^ 1]; if (b < 2) { x->c[h] = y->c[h ^ 1]; z->c[h ^ 1] = b ? x : this; } y->c[i ^ 1] = b ? this : x; fix(); x->fix(); y->fix(); if (p) p->fix(); swap(pp, y->pp); } void splay() { /// Splay this up to the root. Always finishes without flip set. for (pushFlip(); p; ) { if (p->p) p->p->pushFlip(); p->pushFlip(); pushFlip(); int c1 = up(), c2 = p->up(); if (c2 == -1) p->rot(c1, 2); else p->p->rot(c2, c1 != c2); } } Node* first() { /// Return the min element of the subtree rooted at this, splayed to the top. pushFlip(); return c[0] ? c[0]->first() : (splay(), this); } }; struct LinkCut { vector node; LinkCut(int N) : node(N) {} void link(int u, int v) { // add an edge (u, v) assert(!connected(u, v)); makeRoot(&node[u]); node[u].pp = &node[v]; } void cut(int u, int v) { // remove an edge (u, v) Node *x = &node[u], *top = &node[v]; makeRoot(top); x->splay(); assert(top == (x->pp ?: x->c[0])); if (x->pp) x->pp = 0; else { x->c[0] = top->p = 0; x->fix(); } } bool connected(int u, int v) { // are u, v in the same tree? Node* nu = access(&node[u])->first(); return nu == access(&node[v])->first(); } void makeRoot(Node* u) { /// Move u to root of represented tree. access(u); u->splay(); if(u->c[0]) { u->c[0]->p = 0; u->c[0]->flip ^= 1; u->c[0]->pp = u; u->c[0] = 0; u->fix(); } } Node* access(Node* u) { /// Move u to root aux tree. Return the root of the root aux tree. u->splay(); while (Node* pp = u->pp) { pp->splay(); u->pp = 0; if (pp->c[1]) { pp->c[1]->p = 0; pp->c[1]->pp = pp; } pp->c[1] = u; pp->fix(); u = pp; } return u; } }; /* * Status: Przetestowane * Opis: Drzewo potęgowe * Czas: O(\log n) * Użycie: * wszystko indexowane od 0 * update(pos, val) dodaje val do elementu pos * query(pos) zwraca sumę na przedziale [0, pos] */ struct Fenwick { vector s; Fenwick(int n) : s(n) {} void update(int pos, LL val) { for(; pos < ssize(s); pos |= pos + 1) s[pos] += val; } LL query(int pos) { LL ret = 0; for(pos++; pos > 0; pos &= pos - 1) ret += s[pos - 1]; return ret; } LL query(int l, int r) { if(l > r) return 0; return query(r) - (l == 0 ? 0LL : query(l - 1)); } }; // https://ideone.com/No6ksW inline int64_t gilbertOrder(int x, int y, int pow, int rotate) { if (pow == 0) { return 0; } int hpow = 1 << (pow-1); int seg = (x < hpow) ? ( (y < hpow) ? 0 : 3 ) : ( (y < hpow) ? 1 : 2 ); seg = (seg + rotate) & 3; const int rotateDelta[4] = {3, 0, 0, 1}; int nx = x & (x ^ hpow), ny = y & (y ^ hpow); int nrot = (rotate + rotateDelta[seg]) & 3; int64_t subSquareSize = int64_t(1) << (2*pow - 2); int64_t ans = seg * subSquareSize; int64_t add = gilbertOrder(nx, ny, pow-1, nrot); ans += (seg == 1 || seg == 2) ? add : (subSquareSize - add - 1); return ans; } struct Query { int l, r, idx; int64_t ord; inline void calcOrder() { ord = gilbertOrder(l, r, 21, 0); } }; inline bool operator<(const Query &a, const Query &b) { return a.ord < b.ord; } int main() { ios_base::sync_with_stdio(0); cin.tie(0); int n, m; cin >> n >> m; vector> edges(m); for(auto &edge : edges) { cin >> edge.first >> edge.second; --edge.first; --edge.second; } debug(n, m, edges); LinkCut forest(n); int r = -1; vector until(m, -1); for(int l = 0; l < m; ++l) { if(l > 0) forest.cut(edges[l - 1].first, edges[l - 1].second); while(r + 1 < m and not forest.connected(edges[r + 1].first, edges[r + 1].second)) { ++r; forest.link(edges[r].first, edges[r].second); } debug(l, r); until[l] = r; } debug(until); int q; cin >> q; vector queries(q); REP(i, q) { cin >> queries[i].l >> queries[i].r; --queries[i].l; --queries[i].r; queries[i].idx = i; queries[i].calcOrder(); } sort(queries.begin(), queries.end()); LL answer = 0; int cnt_bigger_r = 0; vector cnt_ending_at_r(m); int l = 0; r = -1; auto move_l_right = [&] { answer -= min(until[l], r) - l + 1; if(until[l] > r) --cnt_bigger_r; --cnt_ending_at_r[until[l]]; ++l; }; auto move_l_left = [&] { --l; answer += min(until[l], r) - l + 1; if(until[l] > r) ++cnt_bigger_r; ++cnt_ending_at_r[until[l]]; }; auto move_r_left = [&] { cnt_bigger_r += cnt_ending_at_r[r]; answer -= cnt_bigger_r; --cnt_ending_at_r[until[r]]; --cnt_bigger_r; --answer; --r; }; auto move_r_right = [&] { ++r; answer += cnt_bigger_r; cnt_bigger_r -= cnt_ending_at_r[r]; ++cnt_ending_at_r[until[r]]; ++answer; if(until[r] > r) ++cnt_bigger_r; }; vector ans_for_query(q, -1); for(Query &x : queries) { while(r < x.r) move_r_right(); while(x.l < l) move_l_left(); while(x.r < r) move_r_left(); while(l < x.l) move_l_right(); debug(l, r, answer, cnt_bigger_r, cnt_ending_at_r); ans_for_query[x.idx] = answer; } for(LL a : ans_for_query) cout << a << '\n'; }