您的位置:首页 > 其它

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

2016-02-02 12:06 316 查看


从左到右加边, 假如+的边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
+ '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
->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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: