BZOJ 3514: Codechef MARCH14 GERALD07加强版( LCT + 主席树 )

从左到右加边, 假如+的边e形成环, 那么记下这个环上最早加入的边_e, 当且仅当询问区间的左端点> _e加入的时间, e对答案有贡献(脑补一下). 然后一开始是N个连通块, 假如有x条边有贡献, 答案就是N-x. 用LCT维护加边, 可持久化线段树维护询问. O(NlogN)

------------------------------------------------------------------------------------

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
const int maxn = 200009;
 
int N, M, Q, typ;
int ntr[maxn], par[maxn], sm[maxn], buf[16];
 
inline int getint() {
char c = getchar();
for(; !isdigit(c); c = getchar());
int ret = 0;
for(; isdigit(c); c = getchar())
ret = ret * 10 + c - '0';
return ret;
}
 
inline void putint(int x) {
if(!x) {
puts("0"); return;
}
int n = 0;
for(; x; x /= 10)
buf[n++] = x % 10;
while(n--)
putchar(buf[n] + '0');
puts("");
}
 
int Find(int x) {
return x == par[x] ? x : par[x] = Find(par[x]);
}
 
struct edge {
int u, v;
} e[maxn];
 
struct Node* Null;
 
struct Node {
Node *ch[2], *p, *fa, *mn;
bool iR, rev;
int n;
inline void setc(Node* c, int t) {
(ch[t] = c)->p = this;
}
inline void pd() {
if(rev) {
swap(ch[0], ch[1]);
ch[0]->rev ^= 1;
ch[1]->rev ^= 1;
rev = false;
}
}
inline void upd() {
mn = this;
if(ch[0] != Null && mn->n > ch[0]->mn->n) mn = ch[0]->mn;
if(ch[1] != Null && mn->n > ch[1]->mn->n) mn = ch[1]->mn;
}
inline int d() {
return this == p->ch[1];
}
inline void setR() {
fa = p, p = Null;
iR = true;
}
} pool[maxn << 1], *T, *V[maxn], *stk[maxn << 1];
 
void Init_LCT() {
T = pool;
T->ch[0] = T->ch[1] = T;
T->fa = T->p = T->mn = T;
T->n = maxn;
Null = T++;
}
 
Node* Newnode(int n) {
T->n = n;
T->ch[0] = T->ch[1] = Null;
T->fa = T->p = Null;
T->iR = true, T->rev = false;
return T++;
}
 
void Rot(Node* t) {
Node* p = t->p;
p->pd(), t->pd();
int d = t->d();
p->p->setc(t, p->d());
p->setc(t->ch[d ^ 1], d);
t->setc(p, d ^ 1);
p->upd();
if(p->iR) {
p->iR = false;
t->iR = true;
t->fa = p->fa;
}
}
 
void Splay(Node* t) {
int n = 0;
for(Node* o = t; o != Null; o = o->p) stk[n++] = o;
while(n--) stk[n]->pd();
for(Node* p = t->p; p != Null; p = t->p) {
if(p->p != Null)
p->d() != t->d() ? Rot(t) : Rot(p);
Rot(t);
}
t->upd();
}
 
void Access(Node* t) {
for(Node* o = Null; t != Null; o = t, t = t->fa) {
Splay(t);
t->ch[1]->setR();
t->setc(o, 1);
}
}
 
void makeRoot(Node* t) {
Access(t);
Splay(t);
t->rev ^= 1;
}
 
Node* Path(Node* u, Node* v) {
makeRoot(u);
Access(v), Splay(v);
return v;
}
 
void Join(Node* u, Node* v) {
makeRoot(u);
u->fa = v;
}
 
void Cut(Node* u, Node* v) {
makeRoot(u);
Access(v), Splay(v);
u->p = Null, u->setR();
v->setc(Null, 0), v->upd();
}
 
namespace F {
int Val;
struct Node {
Node *lc, *rc;
int n;
} pool[maxn * 80], *pt, *Null, *Root[maxn];
void Init() {
pt = pool;
pt->lc = pt->rc = pt;
pt->n = 0;
Root[0] = Null = pt++;
}
Node* Modify(Node* t, int l, int r) {
Node* o = pt++;
o->n = t->n + 1;
if(l != r) {
int m = (l + r) >> 1;
if(Val <= m) {
o->lc = Modify(t->lc, l, m);
o->rc = t->rc;
} else {
o->lc = t->lc;
o->rc = Modify(t->rc, m + 1, r);
}
}
return o;
}
}
 
int main() {
N = getint(), M = getint();
Q = getint(), typ = getint();
Init_LCT();
for(int i = 0; i < N; i++)
par[i] = i, V[i] = Newnode(maxn);
for(int i = 1; i <= M; i++) {
int &u = e[i].u, &v = e[i].v;
u = getint() - 1, v = getint() - 1;
if(u == v) {
ntr[i] = maxn;
continue;
}
int _u = Find(u), _v = Find(v);
Node* t = Newnode(i);
if(_u == _v) {
Node* mn = Path(V[u], V[v])->mn;
Cut(V[e[mn->n].u], mn);
Cut(V[e[mn->n].v], mn);
ntr[i] = mn->n;
} else {
ntr[i] = 0;
par[_u] = _v;
}
Join(t, V[u]), Join(t, V[v]);
}
F::Init();
for(int i = 1; i <= M; i++) if(ntr[i] >= 1 && ntr[i] <= M) {
F::Val = ntr[i];
F::Root[i] = F::Modify(F::Root[i - 1], 1, M);
} else 
F::Root[i] = F::Root[i - 1];
sm[0] = 0;
for(int i = 1; i <= M; i++)
sm[i] = sm[i - 1] + !ntr[i];
int ans = 0, l, r;
while(Q--) {
l = getint(), r = getint();
if(typ)
l ^= ans, r ^= ans;
int p = l - 1;
ans = sm[r] - sm[p];
F::Node *L = F::Root[p], *R = F::Root[r];
l = 1, r = M;
while(l < r) {
int m = (l + r) >> 1;
if(m <= p) {
ans += R->lc->n - L->lc->n;
L = L->rc, R = R->rc;
l = m + 1;
} else {
L = L->lc, R = R->lc;
r = m;
}
}
putint(ans = N - ans);
}
return 0;
}

------------------------------------------------------------------------------------

3514: Codechef MARCH14 GERALD07加强版

Time Limit: 40 Sec   Memory Limit: 256 MB
Submit: 685   Solved: 232
[ Submit][ Status][ Discuss]

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。

Source

By zhonghaoxi

 

你可能感兴趣的:(BZOJ 3514: Codechef MARCH14 GERALD07加强版( LCT + 主席树 ))