bzoj3514:Codechef MARCH14 GERALD07加强版 关于一类LCT维护动态图的连通性问题

来源:互联网 发布:hadoop 数据挖掘 编辑:程序博客网 时间:2024/06/05 21:49

3514: Codechef MARCH14 GERALD07加强版

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 1900  Solved: 721
[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。


2016.2.26提高时限至60s

Source

By zhonghaoxi


这是一道关于LCT维护动态图的连通性问题。

先说做法:

1.先将每条边加入图中,然后如果这条边所在两个点已经构成了环,那么把这个环中最早加入的一条边,并把这条边记录为当前边的前驱。early[i]=j

2.那么对于l~r区间的每天边,我们需要的答案就是n-([early[i]<l==1](l<=i<=r))也及n-(l~r中pre小于等于l的边的个数)

About正确性:如果要是early[i]<l说明这条边一定连接了两个连通块,因此这条边减少了一个连同块,对答案的贡献是-1。否则它对答案没有贡献。

维护?:对于1.可以用LCT,对于一条边记其边权是其加入时间戳。然后边权转点权,用LCT维护最小值节点即可。对于2.可以用主席树,查询区间小于某个数的个数即可。

#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>#include<algorithm>#include<map>#include<cmath>#define maxn 440000#define maxt 4400000#define ls ch[p][0]#define rs ch[p][1]#define inf 0x3f3f3f3fusing namespace std;int read() {    char ch = getchar(); int x = 0, f = 1;    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}    while(ch >= '0' && ch <= '9') {x = x * 10 - '0' + ch; ch = getchar();}    return x * f;} int ch[maxn][2], fa[maxn], mn[maxn], val[maxn];bool rev[maxn];int root[maxn], sum[maxt], lc[maxt], rc[maxt], sz;int n, m, Q, type, top, st[maxn], early[maxn], eu[maxn], ev[maxn];bool wh(int p) {return ch[fa[p]][1] == p;}bool Isroot(int p) {return ch[fa[p]][0] != p && ch[fa[p]][1] != p;} void update(int p) {    mn[p] = p;    if(val[mn[p]] > val[mn[ls]]) mn[p] = mn[ls];    if(val[mn[p]] > val[mn[rs]]) mn[p] = mn[rs];}void push_down(int p) {    if(rev[p]) {        rev[ls] ^= 1; rev[rs] ^= 1;        rev[p] ^= 1; swap(ls, rs);    }} void push_up(int p) {    st[top = 1] = p;    for(int i = p; !Isroot(i); i = fa[i]) st[++top] = fa[i];    for(int i = top; i; --i) push_down(st[i]);}  void Rotate(int p) {    int f = fa[p], g = fa[f], c = wh(p);    if(!Isroot(f)) ch[g][wh(f)] = p; fa[p] = g;    ch[f][c] = ch[p][c ^ 1]; if(ch[f][c]) fa[ch[f][c]] = f;    ch[p][c ^ 1] = f; fa[f] = p;    update(f);}  void Splay(int p) {    push_up(p);    for(; !Isroot(p); Rotate(p))         if(!Isroot(fa[p])) Rotate(wh(fa[p]) == wh(p) ? fa[p] : p);    update(p);}  void Access(int p) {    for(int pre = 0; p; pre = p, p = fa[p]) {        Splay(p);        rs = pre;        update(p);    }} void makeroot(int p) {Access(p); Splay(p); rev[p] ^= 1;}void Link(int p, int g) {    makeroot(p);    fa[p] = g;} void Cut(int p, int g) {    makeroot(p); Access(g); Splay(g);    fa[p] = ch[g][0] = 0;} int Query(int u, int v) {    makeroot(u); Access(v); Splay(v);    return mn[v];}int find(int p) {Access(p); Splay(p); while(ls) p = ls; return p;} void add(int L, int R, int pre_p, int &cur_p, int val) {    sum[cur_p = ++sz] = sum[pre_p] + 1;    if(L == R) return;    int mid = L + R >> 1;    if(val <= mid) {        rc[cur_p] = rc[pre_p];        add(L, mid, lc[pre_p], lc[cur_p], val);    }    else {        lc[cur_p] = lc[pre_p];        add(mid + 1, R, rc[pre_p], rc[cur_p], val);    }} void LCT() {    int tot = n;    for(int i = 1;i <= m; ++i) {        int u = read(), v = read();        eu[i] = u; ev[i] = v;        if(u == v) {early[i] = i;continue;}        if(find(u) == find(v)) {            int t = Query(u, v); early[i] = val[t];            Cut(eu[early[i]], t); Cut(ev[early[i]], t);        }        ++tot; mn[tot] = tot; val[tot] = i;        Link(u, tot); Link(v, tot);        }    //for(int i = 1; i <= m; ++i) cout<<early[i]<<" ";    //cout<<endl;    for(int i = 1;i <= m; ++i) add(0, m, root[i - 1], root[i], early[i]);} int query(int L, int R, int lt, int rt, int val) {    if(R == val) return sum[rt] - sum[lt];    int mid = L + R >> 1;    if(val <= mid) return query(L, mid, lc[lt], lc[rt], val);    else return sum[lc[rt]] - sum[lc[lt]] + query(mid + 1, R, rc[lt], rc[rt], val); } void PST() {    int lastans = 0;    while(Q--) {        int l = read(), r = read();        if(type) l ^= lastans, r ^= lastans;        lastans = n - query(0, m, root[l - 1], root[r], l - 1);        printf("%d\n", lastans);    }}  int main(){    n = read(); m = read(); Q = read(); type = read(); val[0] = inf;    for(int i = 1;i <= n; ++i) mn[i] = i, val[i] = inf;    LCT(); PST();    return 0;}


阅读全文
0 0