HDU 5333 Undirected Graph【LCT+BIT】

来源:互联网 发布:霸道总裁 知乎 编辑:程序博客网 时间:2024/06/01 08:11

LCT:
每次操作相当于只把区间[L,R]之间的边连起来,求联通分量的个数。
思路:
把操作排序后,对于区间[L,R]的操作,先把R所有v<R的边(Rv)加入集合, 用动态树+并查集维护[1,R]的联通分量的个数cnt
那么,答案==[L,R]区间的联通分量的个数+NR+L1
求区间[L,R]的联通分量的个数,可以考虑把所有[1,L1]的边删掉后新形成的联通分量。
假设当前的连通分量x为一棵树,那么删掉一条边肯定会形成一个新的连通分量,所以删掉所有[1,L]的边形成的连通分量的个数即
这棵树上所有(uvv<L)的边的数量。
如果当前联通分量是一棵树+一条边的话, 那么,如果树中有|x|1条包含在[L,R]内的边,则不会形成新的连通分量,
考虑到删掉的边的单调性,即如果对于一棵树加入一条新的边uv,那么这条边可以代替所有uvv<v的边,
也就是说v’这条边就算在之后的操作中会被删掉也不会对答案产生影响,因此删掉这条边,并且将新边加入此树。
故区间[L,R]的连通分量的个数即cnt+当前森林中(uv,v<L)的边的数量;
前者可以用LCT+并查集维护,后者可以用树状数组维护。
对于当前新加入的边(uv)如果u和v不在同一个连通分量,则用并查集合并他们并且将他们的LCT合并。
否则的话, 将u所在的LCT中uv这条链的边里面两点最小值最小的那一条边删除,并且在树状数组中将对应点也删除。

(代码来源)

#pragma comment(linker, "/STACK:1024000000")#include <stdio.h>#include <string.h>#include <map>#include <algorithm>using namespace std ;typedef long long LL ;#define clr( a , x ) memset ( a , x , sizeof a )#define ls ( o << 1 )#define rs ( o << 1 | 1 )#define lson ls , l , m#define rson rs , m + 1 , r#define root 1 , 1 , n#define mid ( ( l + r ) >> 1 )const int MAXN = 100005 ;const int MAXE = 200005 ;const int INF = 0x3f3f3f3f ;struct Edge {    int v , idx , n ;    Edge () {}    Edge ( int v , int idx , int n ) : v ( v ) , idx ( idx ) , n ( n ) {}} ;struct Node* null ;struct Node {    Node* c[2] ;    Node* f ;    bool flip ;    int minv , val ;    int eidx , idx ;    void newnode ( int v , int i ) {        c[0] = c[1] = f = null ;        minv = val = v ;        eidx = idx = i ;        flip = 0 ;    }    void rev () {        if ( this == null ) return ;        swap ( c[0] , c[1] ) ;        flip ^= 1 ;    }    void up () {        if ( this == null ) return ;        if ( val <= c[0]->minv && val <= c[1]->minv ) {            minv = val ;            eidx = idx ;        } else if ( c[0]->minv <= c[1]->minv && c[0]->minv <= val ) {            minv = c[0]->minv ;            eidx = c[0]->eidx ;        } else {            minv = c[1]->minv ;            eidx = c[1]->eidx ;        }    }    void down () {        if ( this == null ) return ;        if ( flip ) {            c[0]->rev () ;            c[1]->rev () ;            flip = 0 ;        }    }    bool is_root () {        return f == null || f->c[0] != this && f->c[1] != this ;    }    void sign_down () {        if ( !is_root () ) f->sign_down () ;        down () ;    }    void setc ( Node* o , int d ) {        c[d] = o ;        o->f = this ;    }    void rot ( int d ) {        Node* p = f ;        Node* g = f->f ;        p->setc ( c[d] , !d ) ;        if ( !p->is_root () ) g->setc ( this , f == g->c[1] ) ;        else f = g ;        setc ( p , d ) ;        p->up () ;    }    void splay () {        sign_down () ;        while ( !is_root () ) {            if ( f->is_root () ) rot ( this == f->c[0] ) ;            else {                if ( f == f->f->c[0] ) {                    if ( this == f->c[0] ) f->rot ( 1 ) , rot ( 1 ) ;                    else rot ( 0 ) , rot ( 1 ) ;                } else {                    if ( this == f->c[1] ) f->rot ( 0 ) , rot ( 0 ) ;                    else rot ( 1 ) , rot ( 0 ) ;                }            }        }        up () ;    }    void access () {        Node* o = this ;        for ( Node* x = null ; o != null ; x = o , o = o->f ) {            o->splay () ;            o->setc ( x , 1 ) ;            o->up () ;        }        splay () ;    }    void make_root () {        access () ;        rev () ;    }    void link ( Node* o ) {        make_root () ;        f = o ;    }    void cut () {        access () ;        c[0] = c[0]->f = null ;        up () ;    }    void cut ( Node* o ) {        make_root () ;        o->cut () ;    }    int get_min ( Node* o ) {        make_root () ;        o->access () ;        return o->eidx ;    } } ;Node pool[MAXN + MAXE] ;Node* cur ;Node* node[MAXN] ;Node* edge[MAXE] ;Edge E[MAXE + MAXN] ;int H[MAXN] , Q[MAXN] , cntE ;int U[MAXE] , V[MAXE] ;int ans[MAXN] ;int p[MAXN] ;int c[MAXN] ;int n , m , q ;int find ( int x ) {    return p[x] == x ? x : ( p[x] = find ( p[x] ) ) ;}void init ( int n ) {    cntE = 0 ;    cur = pool ;    cur->newnode ( INF , -1 ) ;    null = cur ++ ;    for ( int i = 1 ; i <= n ; ++ i ) {        p[i] = i ;        H[i] = -1 ;        Q[i] = -1 ;        c[i] = 0 ;        cur->newnode ( INF , -1 ) ;        node[i] = cur ++ ;    }}void addedge ( int u , int v , int idx , int H[] ) {    E[cntE] = Edge ( v , idx , H[u] ) ;    H[u] = cntE ++ ;}void add ( int x , int v ) {    for ( ; x <= n ; x += x & -x ) c[x] += v ;}int sum ( int x , int ans = 0 ) {    for ( ; x > 0 ; x -= x & -x ) ans += c[x] ;    return ans ;}void scanf ( int& x , char c = 0 ) {    while ( ( c = getchar () ) < '0' ) ;    x = c - '0' ;    while ( ( c = getchar () ) >= '0' ) x = x * 10 + c - '0' ;}void solve () {    int cnt = 0 ;    int u , v ;    init ( n ) ;    for ( int i = 1 ; i <= n ; ++ i ) add ( i , -1 ) ;    for ( int i = 0 ; i < m ; ++ i ) {        scanf ( "%d%d" , &u , &v ) ;        if ( u == v ) continue ;        if ( u < v ) swap ( u , v ) ;        addedge ( u , v , i , H ) ;        U[i] = u ;        V[i] = v ;        cur->newnode ( v , i ) ;        edge[i] = cur ++ ;    }    for ( int i = 0 ; i < q ; ++ i ) {        scanf ( "%d%d" , &u , &v ) ;        addedge ( v , u , i , Q ) ;    }    for ( int i = 1 ; i <= n ; ++ i ) {        ++ cnt ;        for ( int j = H[i] ; ~j ; j = E[j].n ) {            int v = E[j].v , idx = E[j].idx ;            if ( v == i ) continue ;            int x = find ( i ) ;            int y = find ( v ) ;            if ( x != y ) {                -- cnt ;                p[x] = y ;                edge[idx]->link ( node[i] ) ;                edge[idx]->link ( node[v] ) ;                add ( v , 1 ) ;            } else {                int eidx = node[i]->get_min ( node[v] ) ;                if ( V[eidx] >= v ) continue ;                edge[eidx]->cut ( node[U[eidx]] ) ;                edge[eidx]->cut ( node[V[eidx]] ) ;                add ( V[eidx] , -1 ) ;                edge[idx]->link ( node[i] ) ;                edge[idx]->link ( node[v] ) ;                add ( v , 1 ) ;            }        }        for ( int j = Q[i] ; ~j ; j = E[j].n ) {            int v = E[j].v , idx = E[j].idx ;            ans[idx] = cnt + sum ( v - 1 ) + n - i + v - 1 ;        }    }    for ( int i = 0 ; i < q ; ++ i ) {        printf ( "%d\n" , ans[i] ) ;    }}int main () {    while ( ~scanf ( "%d%d%d" , &n , &m , &q ) ) solve () ;    return 0 ;}

不同的姿势吧,还是推荐上面那种封装好的,比较方便

//      whn6325689//      Mr.Phoebe//      http://blog.csdn.net/u013007900#include <algorithm>#include <iostream>#include <iomanip>#include <cstring>#include <climits>#include <complex>#include <fstream>#include <cassert>#include <cstdio>#include <bitset>#include <vector>#include <deque>#include <queue>#include <stack>#include <ctime>#include <set>#include <map>#include <cmath>#include <functional>#include <numeric>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define eps 1e-9#define PI acos(-1.0)#define INF 0x3f3f3f3f#define LLINF 1LL<<62#define speed std::ios::sync_with_stdio(false);typedef long long ll;typedef unsigned long long ull;typedef long double ld;typedef pair<ll, ll> pll;typedef complex<ld> point;typedef pair<int, int> pii;typedef pair<pii, int> piii;typedef vector<int> vi;#define CLR(x,y) memset(x,y,sizeof(x))#define CPY(x,y) memcpy(x,y,sizeof(x))#define clr(a,x,size) memset(a,x,sizeof(a[0])*(size))#define cpy(a,x,size) memcpy(a,x,sizeof(a[0])*(size))#define mp(x,y) make_pair(x,y)#define pb(x) push_back(x)#define lowbit(x) (x&(-x))#define MID(x,y) (x+((y-x)>>1))#define ls (idx<<1)#define rs (idx<<1|1)#define lson ls,l,mid#define rson rs,mid+1,r#define root 1,1,ntemplate<class T>inline bool read(T &n){    T x = 0, tmp = 1;    char c = getchar();    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();    if(c == EOF) return false;    if(c == '-') c = getchar(), tmp = -1;    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();    n = x*tmp;    return true;}template <class T>inline void write(T n){    if(n < 0)    {        putchar('-');        n = -n;    }    int len = 0,data[20];    while(n)    {        data[len++] = n%10;        n /= 10;    }    if(!len) data[len++] = 0;    while(len--) putchar(data[len]+48);}//-----------------------------------const int maxn = 300010;struct Query{    int a, b, i;    bool operator < (const Query &rhs) const    {        return b < rhs.b;    }    void input(int ii = 0)    {        scanf("%d%d", &a, &b);        if(a > b) swap(a, b);        i = ii;    }} que[maxn], e[maxn];int n, m, q, ans[maxn], block_tot;int ch[maxn][2], fa[maxn], rt[maxn], miv[maxn];int val[maxn], sum[maxn], rev[maxn];void ins(int x, int c){    for(int i = x; i <= n; i += i&(-i))        sum[i] += c;}int getsum(int x){    int ans = 0;    for(int i = x; i; i -= i&(-i))        ans += sum[i];    return ans;}void update_rev(int r){    if(!r) return;    swap(ch[r][0], ch[r][1]);    rev[r] ^= 1;}void push_up(int x){    int lc = ch[x][0], rc = ch[x][1];    miv[x] = x;    if(val[miv[lc]] < val[miv[x]]) miv[x] = miv[lc];    if(val[miv[rc]] < val[miv[x]]) miv[x] = miv[rc];}void push_down(int r){    if(rev[r])    {        update_rev(ch[r][0]);        update_rev(ch[r][1]);        rev[r] = 0;    }}bool judge(int u, int v){    while(fa[u]) u = fa[u];    while(fa[v]) v = fa[v];    return u == v;}void rotate(int x){    int y = fa[x], kind = ch[y][1]==x;    ch[y][kind] = ch[x][!kind];    fa[ch[y][kind]] = y;    fa[x] = fa[y];    fa[y] = x;    ch[x][!kind] = y;    if(rt[y])        rt[y] = 0, rt[x] = 1;    else        ch[fa[x]][ch[fa[x]][1]==y] = x;    push_up(y);}void P(int r){    if(!rt[r]) P(fa[r]);    push_down(r);}void splay(int x){    P(x);    while(!rt[x])    {        int f = fa[x], ff = fa[f];        if(rt[f])            rotate(x);        else if((ch[ff][1]==f)==(ch[f][1]==x))            rotate(f), rotate(x);        else            rotate(x), rotate(x);    }    push_up(x);}void access(int x){    // return;    for(int t = 0; x; t = x, x = fa[x])    {        splay(x);        rt[ch[x][1]] = 1;        rt[ch[x][1]=t] = 0;        push_up(x);    }}void makeroot(int x){    access(x);    splay(x);    update_rev(x);}void cut(int x, int y){    makeroot(x);    splay(y);    fa[ch[y][0]] = fa[y];    fa[y] = 0;    rt[ch[y][0]] = 1;    ch[y][0] = 0;    push_up(y);}void link(int x, int y){    makeroot(x);    fa[x] = y;}int query(int x, int y){    makeroot(x);    access(y);    splay(y);    return miv[y];}void gao(int u, int v, int i){    // printf("%d %d :: %d %d", u, v, fa[u], fa[v]); cout << endl;    if(judge(u, v))    {        int t = query(u, v);        if(u == v || u <= val[t]) return;        block_tot++;        cut(t, e[t-n-1].a);        cut(t, e[t-n-1].b);        ins(val[t], -1);    }    block_tot--;    val[n+i] = u;    miv[n+i] = n+i;    link(u, n+i);    link(v, n+i);    ins(u, 1);    // for(int j = 1; j <= n+m; j++)    //     printf("%d ", fa[j]);    // cout << "return" << i << ' ' << u << ' ' << v << ' ' << block_tot << endl;}int main(){    while(~scanf("%d%d%d", &n, &m, &q))    {        for(int i = 0; i <= n; i++)            val[i] = INF, sum[i] = 0;        for(int i = 0; i <= n+m; i++)            rev[i] = ch[i][0] = ch[i][1] = fa[i] = 0, rt[i] = 1;        for(int i = 0; i < m; i++)            e[i].input();        sort(e, e+m);        for(int i = 0; i < q; i++)            que[i].input(i);        sort(que, que+q);        block_tot = n;        for(int i = 0, j = 0; i < q; i++)        {            int l = que[i].a, r = que[i].b;            while(j < m && e[j].b <= r)            {                gao(e[j].a, e[j].b, j+1);                j++;                // printf("%d %d___\n", j, m);            }            ans[que[i].i] = block_tot + getsum(l-1);            // printf("%d %d__%d\n", l-1, block_tot, que[i].i);        }        for(int i = 0; i < q; i++)            printf("%d\n", ans[i]);    }    return 0;}
0 0