HDU 6200 边双联通分量 + 并查集 + dfs序 + BIT

6 篇文章 0 订阅
3 篇文章 0 订阅

简略题意:初始给出一张无向图,两种操作:
1. 添加一条 (u,v) 的无向边。
2. 问从 u v的路径上的割边有多少。

假若不考虑添加边的操作,问有多少割边,我们只需要边双联通缩个点成树,树上的每个边都是割边。从而转化成树上两点间距离。从根dfs一下转化成有根树的问题。

现在考虑添加边的过程,其实就是再缩点的过程,先不考虑如何缩点,假如缩了点之后,我们就需要动态更新两点间距离了。对此我们只需要用 dfs 序 + BIT 维护每个点到根的距离即可。每次一个边 (u>v) 如果失去了作用,那么以 v 为根的子树的值都需要1

考虑这个再缩点的过程,其实我们可以用并查集来维护,每个集合的根部点都代表了实际还存在的点。加入我们要把 (u,v) 相连,那么先找到 lc=lca(u,v) ,我们只需要暴力的把 u v lc 靠近,删除连接他们的边对答案的影响即可。

如果觉得我说的不是很清楚,可以参考叉姐的说法QAQ->ICPCCAMP

#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double eps = 1e-8;
int dcmp(double x) { if(fabs(x)<=eps) return 0; return (x>0)?1:-1;};
typedef long long LL;

namespace fastIO{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    #define ll long long
    //fread->read
    bool IOerror=0;
    inline char nc(){
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend){
            p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1){IOerror=1;return -1;}
            //{printf("IO error!\n");system("pause");for (;;);exit(0);}
        }
        return *p1++;
    }
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
    inline int read(int &x){
        bool sign=0; char ch=nc(); x=0;
        for (;blank(ch);ch=nc());
        if (IOerror)return 0;
        if (ch=='-')sign=1,ch=nc();
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
        return 1;
    }
    inline int read(ll &x){
        bool sign=0; char ch=nc(); x=0;
        for (;blank(ch);ch=nc());
        if (IOerror)return 0;
        if (ch=='-')sign=1,ch=nc();
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
        return 1;
    }
    inline int read(double &x){
        bool sign=0; char ch=nc(); x=0;
        for (;blank(ch);ch=nc());
        if (IOerror)return 0;
        if (ch=='-')sign=1,ch=nc();
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
        if (ch=='.'){
            double tmp=1; ch=nc();
            for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
        }
        if (sign)x=-x;
        return 1;
    }
    inline int read(char *s){
        char ch=nc();
        for (;blank(ch);ch=nc());
        if (IOerror)return 0;
        for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
        *s=0;
        return 1;
    }
    inline void read(char &c){
        for (c=nc();blank(c);c=nc());
        if (IOerror){c=-1;return;}
    }
    //fwrite->write
    struct Ostream_fwrite{
        char *buf,*p1,*pend;
        Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
        void out(char ch){
            if (p1==pend){
                fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
            }
            *p1++=ch;
        }
        void print(int x){
            static char s[15],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1);
        }
        void println(int x){
            static char s[15],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1); out('\n');
        }
        void print(ll x){
            static char s[25],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1);
        }
        void println(ll x){
            static char s[25],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1); out('\n');
        }
        void print(double x,int y){
            static ll mul[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,
                1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL,
                100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL};
            if (x<-1e-12)out('-'),x=-x;x*=mul[y];
            ll x1=(ll)floor(x); if (x-floor(x)>=0.5)++x1;
            ll x2=x1/mul[y],x3=x1-x2*mul[y]; print(x2);
            if (y>0){out('.'); for (size_t i=1;i<y&&x3*mul[i]<mul[y];out('0'),++i); print(x3);}
        }
        void println(double x,int y){print(x,y);out('\n');}
        void print(char *s){while (*s)out(*s++);}
        void println(char *s){while (*s)out(*s++);out('\n');}
        void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
        ~Ostream_fwrite(){flush();}
    }Ostream;
    inline void print(int x){Ostream.print(x);}
    inline void println(int x){Ostream.println(x);}
    inline void print(char x){Ostream.out(x);}
    inline void println(char x){Ostream.out(x);Ostream.out('\n');}
    inline void print(ll x){Ostream.print(x);}
    inline void println(ll x){Ostream.println(x);}
    inline void print(double x,int y){Ostream.print(x,y);}
    inline void println(double x,int y){Ostream.println(x,y);}
    inline void print(char *s){Ostream.print(s);}
    inline void println(char *s){Ostream.println(s);}
    inline void println(){Ostream.out('\n');}
    inline void flush(){Ostream.flush();}
};
using namespace fastIO;

namespace solver {
    const int maxn = 100011;
    int n, m;
    vector<int> G[maxn];
    struct A {
        int u, v, next;
    } star[2*maxn];
    stack<int> S;
    int eg, head[maxn], dfn[maxn], low[maxn], towhere[maxn];
    int Dindex, id;
    bool instack[maxn];

    void addedge(int u, int v) {
        ++eg, star[eg] = {u, v, head[u]}, head[u] = eg;
        swap(u, v);
        ++eg, star[eg] = {u, v, head[u]}, head[u] = eg;
    }

    void dfsBCC(int u, int fa) {
        dfn[u] = low[u] = ++Dindex;
        S.push(u);
        instack[u] = 1;
        int v;
        for(int i = head[u]; ~i; i = star[i].next) {
            int v = star[i].v;
            if(v == fa) continue;
            if(!dfn[v]) {
                dfsBCC(v, u);
                low[u] = min(low[v], low[u]);
            } else if(instack[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(low[u] == dfn[u]) {
            id++;
            for(;;) {
                int tmp = S.top();
                S.pop();
                towhere[tmp] = id;
                instack[tmp] = 0;
                if(tmp == u) break;
            }
        }
        return ;
    }

    void init() {
        eg = Dindex = id = 0;
        memset(head, -1, sizeof head);
        while(!S.empty()) S.pop();
        for(int i = 0; i < maxn; i++) G[i].clear();
        memset(dfn, 0, sizeof dfn);
        memset(instack, 0, sizeof instack);
        memset(towhere, 0, sizeof towhere);
    }

    void rebuild() {
        for(int i = 1; i <= eg; i+=2) {
            int u = star[i].u, v = star[i].v;
            u = towhere[u], v = towhere[v];
            if(u == v) continue;
            G[u].push_back(v);
            G[v].push_back(u);
        }
    }

    int time;
    int C[maxn];
    int lowbit(int x) {return x&-x;};
    void add(int x, int v) { for(int i = x; i <= time; i+=lowbit(i)) C[i]+=v; };
    int ask(int x) { int res = 0; for(int i = x; i; i -= lowbit(i)) res += C[i]; return res;};

    int fa[maxn], L[maxn], R[maxn];
    int find(int x) {
        return x == fa[x]? x : fa[x] = find(fa[x]);
    }

    int p[20][maxn];
    int deep[maxn];

    void dfs(int u, int fa) {
        p[0][u] = fa;
        L[u] = ++time;
        for(auto v : G[u])
            if(v != fa) {
                deep[v] = deep[u] + 1;
                dfs(v, u);
            }
        R[u] = time;
    }

    int goup(int x, int len) {
        for(int i = 19; i >= 0; i--)
            if(x != -1 && (len & (1 << i)))
                x = p[i][x];
        return x;
    }

    int lca(int u, int v) {
        if(deep[u] < deep[v]) swap(u, v);
        int d = deep[u] - deep[v];
        u = goup(u, d);
        if(v == u) return u;
        for(int i = 19; i >= 0; i--) {
            if(p[i][u] == p[i][v]) continue;
            u = p[i][u], v = p[i][v];
        }
        return p[0][u];
    }

    int solve() {
        init();
        read(n), read(m);
        for(int i = 1; i <= m; i++) {
            int u, v;
            read(u), read(v);
            addedge(u, v);
        }
        for(int i = 1; i <= n; i++)
            if(!dfn[i]) dfsBCC(i, -1);
        rebuild();

        memset(C, 0, sizeof C);
        time = 0;
        deep[1] = 0;
        dfs(1, -1);

        for(int i = 1; i < 20; i++) {
            for(int j = 1; j <= id; j++) {
                if(p[i-1][j] == -1) p[i][j] = -1;
                else p[i][j] = p[i-1][p[i-1][j]];
            }
        }
        for(int i = 1; i <= id; i++) fa[i] = i, add(L[i], 1), add(R[i]+1, -1);
        int q; read(q);
        for(int i = 1; i <= q; i++) {
            int pt, x, y;
            read(pt); read(x); read(y);
            x = towhere[x], y = towhere[y];
            if(pt == 1) {
                x = find(x), y = find(y);
                if(x == y) continue;
                int lc = lca(x, y);
                lc = find(lc);
                while(lc != x) {
                    add(L[x], -1), add(R[x]+1, 1);
                    fa[x] = lc;
                    x = find(p[0][x]);
                }
                while(lc != y) {
                    add(L[y], -1), add(R[y]+1, 1);
                    fa[y] = lc;
                    y = find(p[0][y]);
                }
            } else {
                x = find(x), y = find(y);
                int lc = lca(x, y);
                lc = find(lc);
                println(ask(L[x]) + ask(L[y]) - 2*ask(L[lc]));
            }
        }
        return 0;
    }
}

int main() {
    int t;
    scanf("%d", &t);
    for(int i = 1; i <= t; i++) {
        print("Case #"),print(i),print(":\n");
        solver::solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值