Description D e s c r i p t i o n
N
N
个点条边的无向图,询问保留图中编号在
[l,r]
[
l
,
r
]
的边的时候图中的联通块个数。
强制在线。
Solution S o l u t i o n
考虑一个森林的连通图个数。
就是点数减边数。
按加入边的时间为边的权值,维护最大生成树。
加入一条边时,若已经联通,就
Cut
C
u
t
掉权值最小的边。
记录一下每条边的
pre
p
r
e
值:表示加入它时
Cut
C
u
t
掉的边的权值。
若不连通则
pre
p
r
e
为
0
0
。
这样对于一个区间中的边来说,只有
pre
p
r
e
值小于
l
l
<script type="math/tex" id="MathJax-Element-23">l</script>才会是树边。
这个东西用主席树维护一下就好啦。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 404040;
const int INF = 1 << 30;
typedef pair<int, int> P;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
inline void read(int &x) {
static char c; x = 0;
for (c = get(); c < '0' || c > '9'; c = get());
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
inline int Min(int a, int b) {
return a < b ? a : b;
}
int n, m, k, x, y, p, ans;
P G[N];
int pre[N];
namespace UFS {
int fa[N], rk[N];
void Init(int n) {
for (int i = 1; i <= n; i++) fa[i] = i;
}
inline int Fa(int x) {
return fa[x] == x ? x : Fa(fa[x]);
}
inline int Merge(int x, int y) {
static int f1, f2;
f1 = Fa(x); f2 = Fa(y);
if (f1 == f2) return 0;
if (rk[f1] < rk[f2]) swap(f1, f2);
if (rk[f1] == rk[f2]) rk[f1]++;
fa[f2] = f1; return 1;
}
}
namespace Seg {
int rt[N];
int Tcnt;
int ls[N * 40], rs[N * 40], sum[N * 40];
inline void Modify(int &o, int l, int r, int pos, int x) {
ls[++Tcnt] = ls[o]; rs[Tcnt] = rs[o];
sum[Tcnt] = sum[o]; o = Tcnt;
if (l == r) return (void)(++sum[o]);
int mid = (l + r) >> 1;
if (pos <= mid) Modify(ls[o], l, mid, pos, x);
else Modify(rs[o], mid + 1, r, pos, x);
sum[o] = sum[ls[o]] + sum[rs[o]];
}
inline int Sum(int o, int l, int r, int L, int R) {
if (!o) return 0;
if (l >= L && r <= R) return sum[o];
int mid = (l + r) >> 1, res = 0;
if (L <= mid) res += Sum(ls[o], l, mid, L, R);
if (R > mid) res += Sum(rs[o], mid + 1, r, L, R);
return res;
}
inline void Add(int i, int res, int x) {
Modify(rt[i], 1, n + m, res, x);
}
inline int Query(int l, int r, int L, int R) {
return Sum(rt[r], 1, n + m, L, R) - Sum(rt[l - 1], 1, n + m, L, R);
}
}
namespace LCT {
struct node {
node *ch[2];
node *fa;
int mn, id, rev;
inline void PushUp(void) {
mn = Min(ch[0]->mn, ch[1]->mn);
mn = Min(id, mn);
}
inline void PushDown(void) {
if (rev) {
swap(ch[0], ch[1]);
ch[0]->rev ^= 1;
ch[1]->rev ^= 1;
rev = 0;
}
}
};
node T[N];
node *null;
inline bool IsRoot(node* x) {
return x->fa == null || (x->fa->ch[0] != x && x->fa->ch[1] != x);
}
inline void Init(int n) {
null = T;
null->ch[0] = null->ch[1] = null->fa = null;
null->mn = INF;
for (int i = 1; i <= n; i++) {
T[i].ch[0] = T[i].ch[1] = T[i].fa = null;
T[i].id = T[i].mn = INF; T[i].rev = 0;
}
}
inline void Rotate(node* x) {
node *y = x->fa, *z = y->fa;
int l = (y->ch[0] != x), r = l ^ 1;
if (!IsRoot(y)) {
if (z->ch[0] == y) z->ch[0] = x;
else z->ch[1] = x;
}
x->fa = z; y->fa = x; x->ch[r]->fa = y;
y->ch[l] = x->ch[r]; x->ch[r] = y;
y->PushUp(); x->PushUp();
}
inline void Down(node* x) {
if (!IsRoot(x)) Down(x->fa);
x->PushDown();
}
inline void Splay(node* x) {
Down(x);
while (!IsRoot(x)) {
node *y = x->fa, *z = y->fa;
if (!IsRoot(y)) {
if (y->ch[0] == x ^ z->ch[0] == y) Rotate(x);
else Rotate(y);
}
Rotate(x);
}
}
inline void Access(node* x) {
for (node *y = null; x != null; x = x->fa) {
Splay(x); x->ch[1] = y;
x->PushUp(); y = x;
}
}
inline void MakeRoot(node* x) {
Access(x); Splay(x); x->rev ^= 1;
}
inline void Link(node* x, node* y) {
MakeRoot(x); x->fa = y;
}
inline void Cut(node* x, node* y) {
MakeRoot(x); Access(y); Splay(y);
x->fa = y->ch[0] = null; y->PushUp();
}
inline int Query(node* x, node* y) {
MakeRoot(x); Access(y); Splay(y);
return y->mn;
}
inline void AddEdge(int x, int y, int pos) {
Seg::rt[pos] = Seg::rt[pos - 1];
if (x == y) return;
G[n + pos] = P(x, y);
T[n + pos].id = T[n + pos].mn = n + pos;
int res = n;
if (!UFS::Merge(x, y)) {
res = Query(T + x, T + y);
Cut(T + res, T + G[res].first);
Cut(T + res, T + G[res].second);
}
pre[pos] = res;
Seg::Add(pos, res, 1);
Link(T + n + pos, T + x);
Link(T + n + pos, T + y);
}
}
int main(void) {
read(n); read(m); read(k); read(p);
LCT::Init(n + m); UFS::Init(n);
for (int i = 1; i <= m; i++) {
read(x); read(y);
LCT::AddEdge(x, y, i);
}
for (int i = 1; i <= k; i++) {
read(x); read(y);
if (p) {
x ^= ans; y ^= ans;
}
printf("%d\n", ans = n - Seg::Query(x, y, n, n + x - 1));
}
return 0;
}