【BZOJ3514】Codechef MARCH14 GERALD07加强版
Description
\(N\)个点\(M\)条边的无向图,询问保留图中编号在\([l,r]\)的边的时候图中的联通块个数。
Input
第一行四个整数\(N、M、K、type\),代表点数、边数、询问数以及询问是否加密。
接下来\(M\)行,代表图中的每条边。
接下来\(K\)行,每行两个整数\(L\)、\(R\)代表一组询问。对于\(type=0\)的测试点,读入的\(L\)和\(R\)即为询问的\(L\)、\(R\);对于\(type=1\)的测试点,每组询问的\(L、R\)应为\(L\) \(xor\) \(lastans\)和\(R\) \(xor\) \(lastans\)。
Output
\(K\)行每行一个整数代表该组询问的联通块个数。
Sample Input
3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2
Sample Output
2
1
3
1
HINT
对于\(100%\)的数据,\(1≤N、M、K≤200,000\)。
联通块个数等于 点数-有效边数,这里的有效边也可以理解为树边,我们可以从前往后加边,用\(lct\)维护生成树,
设当前边\(i\)连接\(x\)和\(y\),如果\(x\)和\(y\)联通了,连上\(i\)并换掉路径上最早的一条边\(j\),并记录\(a[i] = j\),也就是\(i\)边替换掉了\(j\)边
如果\(x\),\(y\)不联通,连上\(i\)后,记录\(a[i] = 0\),注意判自环,不连边,\(a[i] = i\),这样用\(lct\)处理出\(1 <= i <= n\)的\(a[i]\)
对于只有\([l, r]\)的边的图,有效边数也就是\(\sum _{i = l}^{r}[a[i] < l]\),多组询问,主席树维护\(a[i]\),在线查询
Code
#include <bits/stdc++.h>
#define rint register int
#define F(x) (t[x].fa)
#define L(x) (t[x].ch[0])
#define R(x) (t[x].ch[1])
#define get(x) (x == t[F(x)].ch[1])
#define not_root(x) (x == t[F(x)].ch[0] || x == t[F(x)].ch[1])
#define Rev(x) ({ std:: swap(L(x), R(x)), t[x].rev ^= 1; })
const int maxn = 200000 + 10;
const int inf = 1e9;
int n, m, q, typ, last_ans;
int sta[maxn * 2];
int a[maxn], ex[maxn], ey[maxn];
int read(rint x = 0, register bool f = 0, register char ch = getchar()){
for(;!isdigit(ch);ch = getchar()) f |= ch == '-';
for(; isdigit(ch);ch = getchar()) x = (x << 3) + (x << 1) + (ch & 15);
return f ? -x : x ;
}
struct Node{
bool rev;
int val, pos;
int fa, ch[2];
}t[maxn * 2];
int tot, root[maxn];
struct Seg{
int siz, ls, rs;
}T[maxn * 25];
void up(rint x){
t[x].pos = x > n ? x : 0;
if(L(x) && t[t[L(x)].pos].val < t[t[x].pos].val) t[x].pos = t[L(x)].pos;
if(R(x) && t[t[R(x)].pos].val < t[t[x].pos].val) t[x].pos = t[R(x)].pos;
}
void down(rint x){
if(t[x].rev){
if(L(x)) Rev(L(x));
if(R(x)) Rev(R(x));
t[x].rev = 0;
}
}
void add(rint x, rint f, rint d){
if(x) F(x) = f;
if(f) t[f].ch[d] = x;
}
void rotate(rint x){
rint y = F(x), z = F(y), gx = get(x), gy = get(y);
if(not_root(y)) add(x, z, gy);
else F(x) = z;
add(t[x].ch[gx ^ 1], y, gx), add(y, x, gx ^ 1);
up(y);
}
void splay(rint x){
rint y = x, z = 0;
sta[++z] = y;
while(not_root(y)) sta[++z] = y = F(y);
while(z) down(sta[z--]);
while(not_root(x)){
y = F(x);
if(not_root(y)) get(x) != get(y) ? rotate(x) : rotate(y);
rotate(x);
}
up(x);
}
void access(rint x){
for(rint y = 0; x ;y = x, x = F(x)){
splay(x), R(x) = y, up(x);
}
}
void make_root(rint x){
access(x), splay(x), Rev(x);
}
int find_root(rint x){
access(x), splay(x);
while(L(x)) x = L(x);
splay(x);
return x;
}
void link(rint x, rint y){
make_root(x);
if(find_root(y) != x) F(x) = y;
}
void cut(rint x, rint y){
make_root(x);
if(find_root(y) == x && F(y) == x && !L(y)){
F(y) = R(x) = 0, up(x);
}
}
#define l(x) (T[x].ls)
#define r(x) (T[x].rs)
void ins(int &rt, rint rt2, rint l, rint r, rint v){
T[rt = ++tot] = T[rt2], T[rt].siz++;
if(l == r) return;
rint mid = (l + r) / 2;
if(v <= mid) ins(l(rt), l(rt2), l, mid, v);
else ins(r(rt), r(rt2), mid + 1, r, v);
}
int query(rint rt, rint rt2, rint l, rint r, rint v){
if(l == r) return (l > v) ? 0 : (T[rt].siz - T[rt2].siz);
rint mid = (l + r) / 2;
if(v <= mid) return query(l(rt), l(rt2), l, mid, v);
return T[l(rt)].siz - T[l(rt2)].siz + query(r(rt), r(rt2), mid + 1, r, v);
}
int main(){
#ifdef lzx
freopen("1.in","r",stdin);
#endif
t[0].val = inf;
n = read(), m = read(), q = read(), typ = read();
for(rint i = 1, x, y;i <= m; ++i){
ex[i] = x = read(), ey[i] = y = read();
if(x == y){ a[i] = i;continue; } // 注意自环
if(find_root(x) != find_root(y)) a[i] = 0;
else{
make_root(x), access(y), splay(y);
rint id = t[y].pos - n;
a[i] = id;
cut(ex[id], n + id);
cut(n + id , ey[id]);
}
t[n + i].val = i, t[n + i].pos = n + i;
link(x, n + i), link(n + i, y);
}
for(rint i = 1;i <= m; ++i) ins(root[i], root[i - 1], 0, m, a[i]);
for(rint i = 1, l, r;i <= q; ++i){
l = read() ^ (last_ans * typ), r = read() ^ (last_ans * typ);
printf("%d\n", last_ans = (n - query(root[r], root[l - 1], 0, m, l - 1)));
}
return 0;
}