\(N\) 個點 \(M\) 條邊的無向圖,詢問保留圖中編號在 \([l,r]\) 的邊的時候圖中的聯通塊個數。node
\(K\) 次詢問強制在線。c++
\(1\le N,M,K \le 200,000\)git
從前日後依次考慮每一條邊,若是加入這條邊 \(i\) 會生成環,那就刪除這個環裏最先加入的邊 \(j\) ,而且記錄下來 \(fout[i] = j\) ,表明 \(i\) 的加入彈掉了 \(j\) 號邊 。ide
也就是說咱們動態維護一顆以插入時間爲權值的最大生成樹,維護這個 \(MST\) 用 \(LCT\) 化邊爲點的 \(Link, Cut\) 就好了。spa
而後發現對於一個詢問 \([l, r]\) ,就看在 \(l\) 到 \(r\) 之間有多少條邊 \(i\) , \(fout[i] < l\) ,而後用 \(n\) 減掉這個數,就是一次詢問的答案 。debug
緣由:code
若是 \(i\) 邊的 \(fout\) 小於 \(l\) ,那麼若是隻存在 \(l\) 到 \(r\) 的邊話, \(i\) 邊一定會鏈接上兩個聯通塊, 答案就要 \(-1\) ;get
反之,若是它的 \(fout\) 大於等於 \(l\) ,那麼這條邊連的是一個聯通塊裏的兩個點,不會對答案產生貢獻 。it
而後對於後面這個區間查 \(<\) 一個數的數有多少個用主席樹維護就好了。ast
注意,自環的 \(fout\) 應該設成 \(\infty\) ,由於它沒法減小聯通塊數量。
ps: 它的強制在線很迷,直接異或就好了。。也不須要交換,以及強制在 \([1, n]\) 之間。。我懷疑沒有在線的點。
對於這類區間詢問聯通塊或者一類有關出現次數的題,咱們經常能夠維護一個 \(Last\) 或者 \(fout\) ,而後查詢區間中和這些信息有關的東西,這個又經常使用主席樹維護,算是一類套路了吧。
具體實現見代碼,寫的有點長,可是閱讀仍是不難。
#include <bits/stdc++.h> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Set(a, v) memset(a, v, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define debug(x) cout << #x << ": " << (x) << endl #define DEBUG(...) fprintf(stderr, __VA_ARGS__) #define fir first #define sec second #define mp make_pair using namespace std; typedef pair<int, int> PII; template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;} template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;} inline int read() { int x(0), sgn(1); char ch(getchar()); for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1; for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48); return x * sgn; } void File() { #ifdef zjp_shadow freopen ("3514.in", "r", stdin); freopen ("3514.out", "w", stdout); #endif } int n, m, k, type; const int N = 2e5 + 1e3; #define ls(o) ch[o][0] #define rs(o) ch[o][1] template<int Maxn> struct Link_Cut_Tree { int ch[Maxn][2], fa[Maxn]; inline bool is_root(int o) { return ls(fa[o]) != o && rs(fa[o]) != o; } inline bool get(int o) { return rs(fa[o]) == o; } PII val[Maxn], minv[Maxn]; inline void push_up(int o) { minv[o] = min(min(minv[ls(o)], minv[rs(o)]), val[o]); } inline void rotate(int v) { int u = fa[v], t = fa[u], d = get(v); fa[ch[u][d] = ch[v][d ^ 1]] = u; fa[v] = t; if (!is_root(u)) ch[t][rs(t) == u] = v; fa[ch[v][d ^ 1] = u] = v; push_up(u); push_up(v); } bool rev[Maxn]; inline void Get_Rev(int o) { rev[o] ^= 1; swap(ls(o), rs(o)); } inline void push_down(int o) { if (rev[o]) Get_Rev(ls(o)), Get_Rev(rs(o)), rev[o] = false; } void Push_All(int o) { if (!is_root(o)) Push_All(fa[o]); push_down(o); } inline void Splay(int o) { Push_All(o); for (; !is_root(o); rotate(o)) if (!is_root(fa[o])) rotate(get(o) != get(fa[o]) ? o : fa[o]); } inline void Access(int o) { for (int t = 0; o; o = fa[t = o]) Splay(o), rs(o) = t, push_up(o); } inline void Make_Root(int o) { Access(o); Splay(o); Get_Rev(o); } inline int Find_Root(int o) { Access(o); Splay(o); while (ls(o)) o = ls(o), push_down(o); Splay(o); return o; } inline void Split(int v, int u) { Make_Root(v); Access(u); Splay(u); } inline void Link(int v, int u) { Split(v, u); fa[v] = u; } inline void Cut(int v, int u) { Split(v, u); fa[v] = ls(u) = 0; } }; Link_Cut_Tree<N << 1> T; int font[N]; template<int Maxn> struct President_Tree { int ls[Maxn], rs[Maxn], sumv[Maxn], Size; void Update(int &o, int pre, int l, int r, int up) { o = ++ Size; ls[o] = ls[pre]; rs[o] = rs[pre]; sumv[o] = sumv[pre] + 1; if (l == r) return ; int mid = (l + r) >> 1; if (up <= mid) Update(ls[o], ls[pre], l, mid, up); else Update(rs[o], rs[pre], mid + 1, r, up); } int Query(int x, int y, int l, int r, int qr) { if (r <= qr) return sumv[y] - sumv[x]; int mid = (l + r) >> 1, res = Query(ls[x], ls[y], l, mid, qr); if (qr > mid) res += Query(rs[x], rs[y], mid + 1, r, qr); return res; } }; President_Tree<N * 20> PT; int rt[N]; int main () { File(); n = read(); m = read(); k = read(); type = read(); For (i, 0, n) T.val[i] = T.minv[i] = mp(m + 1, i); For (i, 1, m) { int node = i + n; T.val[node] = T.minv[node] = mp(i, node); int u = read(), v = read(); if (u != v) { T.Make_Root(u); if (T.Find_Root(v) == u) { T.Split(u, v); PII p = T.minv[v]; font[i] = p.fir; T.Cut(u, p.sec); T.Cut(v, p.sec); } T.Link(u, node); T.Link(v, node); } else font[i] = m; PT.Update(rt[i], rt[i - 1], 0, m, font[i]); } int ans = 0; For (i, 1, k) { int l = read() ^ (type * ans), r = read() ^ (type * ans); if (l > r) ans = 0; else ans = n - PT.Query(rt[l - 1], rt[r], 0, m, l - 1); printf ("%d\n", ans); } return 0; }