给一个n个点m条边的无向图,k次询问只保留编号在[l,r]中的边时图中的联通块个数,强制在线。
$$n,m,k \leq 2\times 10^5$$
依次插入边,用LCT维护生成森林。插入第$i$条边时,如果形成环,就把环上编号最小的边删掉,并记$pre_i$为删掉的边的编号。每次查询时,$[l,r]$中$pre_i<l$的边可以将联通块个数-1,反之不行,用主席树维护即可。
const int MAXN = 200000 + 5, LOG = 25; struct Input { char buf[1 << 25], *s; Input() { #ifdef LOCAL freopen("BZOJ3514.in", "r", stdin); freopen("BZOJ3514.out", "w", stdout); #endif fread(s = buf, 1, 1 << 25, stdin); } friend Input &operator>>(Input &io, int &x) { x = 0; while (!isdigit(*io.s)) ++ io.s; while (isdigit(*io.s)) x = x * 10 + *io.s ++ - '0'; return io; } } cin; struct LinkCutTree { struct Node { Node *fa, *ch[2]; int pre, next, first, last, min; bool flip; Node() { fa = ch[0] = ch[1] = NULL; pre = next = first = last = min = INF; flip = 0; } bool relation() { return this == fa->ch[1]; } bool is_root() { return !fa || (fa->ch[0] != this && fa->ch[1] != this); } void push_up() { min = INF; if (ch[0]) { chkmin(min, pre); chkmin(min, ch[0]->min); first = ch[0]->first; } else { first = pre; } if (ch[1]) { chkmin(min, next); chkmin(min, ch[1]->min); last = ch[1]->last; } else { last = next; } } void push_down() { if (flip) { FOR(i, 0, 2) { if (ch[i]) { std::swap(ch[i]->pre, ch[i]->next); std::swap(ch[i]->first, ch[i]->last); ch[i]->flip ^= 1; } } std::swap(ch[0], ch[1]); flip = 0; } } } *node[MAXN]; void make_tree(int n) { For(i, 1, n) { node[i] = new Node(); } } void rotate(Node *o) { Node *par = o->fa; int dir = o->relation(); par->ch[dir] = o->ch[dir ^ 1]; if (o->ch[dir ^ 1]) { o->ch[dir ^ 1]->fa = par; } if (!par->is_root()) { par->fa->ch[par->relation()] = o; } o->fa = par->fa; par->fa = o; o->ch[dir ^ 1] = par; par->push_up(); o->push_up(); } void splay(Node *o) { static Node *stack[MAXN]; int top = 0; Node *temp = o; for (stack[++ top] = temp; !temp->is_root(); temp = temp->fa) { stack[++ top] = temp->fa; } Rep(i, top, 1) { stack[i]->push_down(); } for (; !o->is_root(); rotate(o)) { if (!o->fa->is_root()) { rotate(o->fa->relation() == o->relation() ? o->fa : o); } } } #define _first(x) ((x) ? x->first : INF) void access(Node *o) { for (Node *temp = NULL; o; temp = o, o = o->fa) { splay(o); o->ch[1] = temp; if (temp) temp->fa = o; o->next = _first(temp); o->push_up(); } } void make_root(Node *o) { access(o); splay(o); o->flip = 1; std::swap(o->pre, o->next); std::swap(o->first, o->last); } Node *find_root(Node *o) { access(o); splay(o); for (o->push_down(); o->ch[0]; o->push_down()) { o = o->ch[0]; } splay(o); return o; } int query(Node *o, Node *p) { make_root(o); access(p); splay(p); return p->min; } void link(Node *o, Node *p, int val) { make_root(p); p->fa = o; p->pre = val; p->push_up(); } void cut(Node *o, Node *p) { make_root(o); access(p); splay(p); p->ch[0] = o->fa = NULL; o->next = p->pre = INF; p->push_up(); o->push_up(); } } T; struct PresidentTree { int ch[2][MAXN * LOG], sum[MAXN * LOG], root[MAXN], cnt; void insert(int &o, int p, int l, int r, int x) { o = ++ cnt; ch[0][o] = ch[0][p], ch[1][o] = ch[1][p], sum[o] = sum[p] + 1; if (l == r) { return; } int mid = (l + r) >> 1; if (x <= mid) { insert(ch[0][o], ch[0][p], l, mid, x); } else { insert(ch[1][o], ch[1][p], mid + 1, r, x); } } int query(int o, int p, int l, int r, int x) { if (l == r) return sum[o] - sum[p]; int mid = (l + r) >> 1; if (x <= mid) return query(ch[0][o], ch[0][p], l, mid, x); else return query(ch[1][o], ch[1][p], mid + 1, r, x) + sum[ch[0][o]] - sum[ch[0][p]]; } } Seg; struct Edge { int from, to; } edge[MAXN]; int main() { int n, m, k, type; cin >> n >> m >> k >> type; T.make_tree(n); For(i, 1, m) { cin >> edge[i].from >> edge[i].to; if (edge[i].from == edge[i].to) { Seg.insert(Seg.root[i], Seg.root[i - 1], 0, m, i); continue; } if (T.find_root(T.node[edge[i].from]) == T.find_root(T.node[edge[i].to])) { int num = T.query(T.node[edge[i].from], T.node[edge[i].to]); T.cut(T.node[edge[num].from], T.node[edge[num].to]); T.link(T.node[edge[i].from], T.node[edge[i].to], i); Seg.insert(Seg.root[i], Seg.root[i - 1], 0, m, num); } else { T.link(T.node[edge[i].from], T.node[edge[i].to], i); Seg.insert(Seg.root[i], Seg.root[i - 1], 0, m, 0); } } int last_ans = 0; For(i, 1, k) { int l, r; cin >> l >> r; if (type) { l ^= last_ans; r ^= last_ans; } printf("%d\n", last_ans = n - Seg.query(Seg.root[r], Seg.root[l - 1], 0, m, l - 1)); } return 0; }