/*{{{*/ #include #ifdef LOCAL int c_ = 0; #define cout (c_?cerr:cout) #define debug(...) \ {if(!c_++)cerr<<"\033[96;1m"; \ __VA_ARGS__; \ if(!--c_)cerr<<"\033[0m";} #else #define debug(...) {} #endif #define assrt(...) debug(\ if (not (__VA_ARGS__)) \ exit((cerr << __LINE__ << ": " << #__VA_ARGS__ << '\n', 0));\ ) #define st first #define nd second #define all(...) (__VA_ARGS__).begin(), (__VA_ARGS__).end() using namespace std; using ll = long long; using ld = long double; template < typename t > using V = vector< t >; template < typename t, size_t s > using A = array< t, s >; void print() {cout << '\n';} template< typename t, typename... v > void print(const t& a, const v&... b) {cout << a << (sizeof...(b)?" ":""); print(b...);} template< typename t > void print_range(t a, const t& b) { while (a != b) cout << (*a++) << ' '; cout << '\n';} #define dump(...) debug(print(#__VA_ARGS__,'=',__VA_ARGS__)) #define dump_range(...) debug(cerr<<#__VA_ARGS__ << ": "; print_range(__VA_ARGS__)) /*}}}*/ constexpr int nax = 1e5, maxm = 1e5, qax = 1e5, sqr = 317; struct Node { int pt; int siz; bool fajen; bool touched; }; int n, m, q, lo[maxm]; ll sums[maxm]; pair tab[maxm]; vector to_clear; vector> back; Node fu[nax + 1]; int find(const int v) { return fu[v].pt == v? v : fu[v].pt = find(fu[v].pt); } int find_with_back(const int v) { return fu[v].pt == v? v : find_with_back(fu[v].pt); } void touch_node(const int v) { if (not fu[v].touched) { fu[v].touched = true; to_clear.push_back(v); } } bool join(int p, int q) { p = find(p); q = find(q); if (p == q) return false; touch_node(p); touch_node(q); if (fu[p].siz > fu[q].siz) swap(p, q); fu[q].siz += fu[p].siz; fu[p].pt = q; fu[q].fajen |= fu[p].fajen; return true; } void fu_back() { for (int i = (int)(back.size()) - 1; i >= 0; --i) { fu[back[i].st] = back[i].nd; } back.clear(); } bool join_with_back(int p, int q) { p = find_with_back(p); q = find_with_back(q); if (p == q) return false; back.push_back({p, fu[p]}); back.push_back({q, fu[q]}); if (fu[p].siz > fu[q].siz) swap(p, q); fu[q].siz += fu[p].siz; fu[p].pt = q; fu[q].fajen |= fu[p].fajen; return true; } void reset_fu_node(const int v) { fu[v].pt = v; fu[v].siz = 1; fu[v].fajen = false; fu[v].touched = false; } void reset_fu() { for (int v : to_clear) { reset_fu_node(v); } to_clear.clear(); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; to_clear.reserve(m); back.reserve(n); for (int i = 0; i < m; ++i) { cin >> tab[i].st >> tab[i].nd; } for (int i = 1; i <= n; ++i) { reset_fu_node(i); } int mid = -1; do { mid = min(m - 1, mid + sqr); // inside one block for (int i = max(0, mid - sqr + 1); i <= mid; ++i) { reset_fu(); for (int j = i; j >= max(0, mid - sqr + 1); --j) { if (not join(tab[j].st, tab[j].nd)) { lo[i] = max(lo[i], j + 1); break; } } } reset_fu(); // mark cool vertices for (int i = mid; i > max(-1, mid - sqr); --i) { fu[tab[i].st].fajen = true; fu[tab[i].nd].fajen = true; touch_node(tab[i].st); touch_node(tab[i].nd); } for (int i = mid + 1; i < m; ++i) { if (find(tab[i].st) == find(tab[i].nd)) { lo[i] = max(lo[i], mid + 1); break; } if (fu[find(tab[i].st)].fajen and fu[find(tab[i].nd)].fajen) { join(tab[i].st, tab[i].nd); for (int j = mid; j >= max(0, mid - sqr + 1); --j) { if (not join_with_back(tab[j].st, tab[j].nd)) { lo[i] = max(lo[i], j + 1); break; } } fu_back(); } else { join(tab[i].st, tab[i].nd); } } } while (mid != m - 1); for (int i = 1; i < m; ++i) { lo[i] = max(lo[i], lo[i - 1]); } dump_range(lo, lo + m); for (int i = 0; i < m; ++i) { sums[i] = i - lo[i] + 1; } dump_range(sums, sums + m); for (int i = 1; i < m; ++i) { sums[i] += sums[i - 1]; } cin >> q; for (int i = 0; i < q; ++i) { int a, b; cin >> a >> b; --a, --b; int l = a; int r = b + 1; while (l < r) { int mid = (l + r) / 2; if (lo[mid] >= a) { r = mid; } else { l = mid + 1; } } ll res = 0; if (l > 0) { res = sums[b] - sums[l - 1]; } else { res = sums[b]; } dump(a, b, l); int g = l - 1 - a + 1; dump(g); res += ((ll)g * (g + 1)) / 2; cout << res << '\n'; } }