1. 程式人生 > >hdu5458 LCA+並查集+樹狀陣列

hdu5458 LCA+並查集+樹狀陣列

題意:給出n個點、m條邊(可能有環、重邊)、q個詢問~~
詢問1:=刪除某一條邊<a,b>  

詢問2:=問<a,b>路徑中有多少條橋~~~

橋、如果將環收縮的話,圖會變成一個樹。那麼有多少條橋也就是問路徑<a,b>的大小。

即deep[a]+deep[b]-a*deep[lca(a,b)].

首先圖是刪邊的,很麻煩~~所有離線逆過來處理。

對於要“新增的邊“先標記。

利用剩下的沒有動過的邊跑一趟dfs序成一個完整的樹

並記錄下deep[](深度),當前節點對應的編號idx、當前節點子樹的區間lr[u]....

然後利用剛才沒有用過的非新增的邊進行縮點,當每減少一條橋,某一刻孩子樹將會往上提高一個高度。

這個資訊可以用樹狀陣列進行維護~~~~

同時也用一個並查集維護縮點資訊~~~

#include <algorithm>
#include <iostream>
#include<string.h>
#include <fstream>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define exp 1e-8
#define fi first
#define se second
#define ll long long
#define INF 0x3f3f3f3f
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define all(a) a.begin(),a.end()
#define mm(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define rep(a,b,c) for(int a=b;a<=c;a++)//b---c
#define repp(a,b,c)for(int a=b;a>=c;a--)///
#define stl(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
using namespace std;
void bug(string m="here"){cout<<m<<endl;}
template<typename __ll> inline void READ(__ll &m){__ll x=0,f=1;char ch=getchar();while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}m=x*f;}
template<typename __ll>inline void read(__ll &m){READ(m);}
template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c){READ(m);READ(a);READ(b);READ(c);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c,__ll &d){READ(m);READ(a);READ(b);READ(c);read(d);}
template < class T > T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template < class T > T lcm(T a, T b) { return a / gcd(a, b) * b; }
template < class T > inline void rmin(T &a, const T &b) { if(a > b) a = b; }
template < class T > inline void rmax(T &a, const T &b) { if(a < b) a = b; }
template < class T > T pow(T a, T b) { T r = 1; while(b > 0) { if(b & 1) r = r * a; a = a * a; b /= 2; } return r; }
template < class T > T pow(T a, T b, T mod) { T r = 1; while(b > 0) { if(b & 1) r = r * a % mod; a = a * a % mod; b /= 2; } return r; }

const int maxn=30010;
int n,m,q;
int idx[maxn];
int kk,lr[maxn][3];
int deep[maxn];
int fa[maxn][20];
int belong[maxn];
struct edge
{
    int v,del;
    edge(){}
    edge(int vv){v=vv,del=0;}
    bool operator < (const edge &rhs) const{
        if(v!=rhs.v)return v<rhs.v;
        return del>rhs.del;
    }
};
vector<edge>vec[maxn];
struct QUERY
{
    int op,a,b,ans;
    void READ()
    {
        read(op,a,b);
        ans=-1;
        if(op==1)
        {
            lower_bound(all(vec[a]),edge(b))->del=1;
            lower_bound(all(vec[b]),edge(a))->del=1;
        }
    }
}query[100010];
void init()
{
    kk=1;
    for1(i,n)vec[i].clear();
    for1(i,n)belong[i]=i;
    memset(deep,0,sizeof deep);
}
void dfs_id(int u,int ff,int dee)
{
    deep[u]=dee;
    fa[u][0]=ff;
    lr[u][1]=kk;
    for(int i=0;i<vec[u].size();i++)
    {
        if(vec[u][i].del==1)continue;
        int v=vec[u][i].v;
        if(v==ff)
        {

            vec[u].erase(vec[u].begin()+i);///刪除與父親的聯絡啦~~~~
            i--;
            continue;
        }
        if(deep[v]!=0)continue;
        vec[u].erase(vec[u].begin()+i);///刪除與孩子的聯絡啦~~~~
        i--;
        dfs_id(v,u,dee+1);
    }
    idx[u]=lr[u][2]=kk++;
}
struct LCA
{
    void init()
    {
        ///p[i][j]表示i結點的第2^j祖先
        for(int j=1;(1<<j)<=n;j++)
            for(int i=1;i<=n;i++)
                if(fa[i][j-1]!=-1)
                    fa[i][j]=fa[fa[i][j-1]][j-1];///i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先
    }
    int ask(int a,int b)///最近公共祖先
    {
        int i,j;
        if(deep[a]<deep[b])swap(a,b);
        for(i=0;(1<<i)<=deep[a];i++);
        i--;
        ///使a,b兩點的深度相同
        for(j=i;j>=0;j--)
            if(deep[a]-(1<<j)>=deep[b])
                a=fa[a][j];
        if(a==b)return a;
        ///倍增法,每次向上進深度2^j,找到最近公共祖先的子結點
        for(j=i;j>=0;j--)
        {
            if(fa[a][j]!=-1&&fa[a][j]!=fa[b][j])
            {
                a=fa[a][j];
                b=fa[b][j];
            }
        }
        return fa[a][0];
    }
}lca;
struct bit_tree
{
    int Tree[maxn];
    inline int lowbit(int x){return x&-x;}
    void init()
    {
        memset(Tree,0,sizeof Tree);
    }
    void modify(int x,int y,int val)
    {
        doit(x,val);
        doit(y+1,-val);
    }
    void doit(int x,int val)
    {
        for(int i=x;i<=n;i+=lowbit(i)) //n為區間總長度,1---n
            Tree[i]+=val;
    }
    int sum(int x)
    {
        int res=0;
        for(int i=x;i>0;i-=lowbit(i))
            res+=Tree[i];
        return res;
    }
}tree;
int find(int k)
{
    if(belong[k]!=k)
        belong[k]=find(belong[k]);
    return belong[k];
}
void merge_fa(int a,int b)
{
    a=find(a);
    b=find(b);
    while(a!=b)
    {
        int par=find(fa[a][0]);///
        belong[a]=par;
        tree.modify(lr[a][1],lr[a][2],-1);
        a=par;
    }
}
void merge(int a,int b)
{
    int l=lca.ask(a,b);
    merge_fa(a,l);
    merge_fa(b,l);
}
void merge_ret()
{
    for(int u=1;u<=n;u++)
        for(int i=0;i<vec[u].size();i++)
        {
            if(vec[u][i].del==1)continue;
            merge(u,vec[u][i].v);
        }
}
int get_ans(int a,int b)
{
    int l=lca.ask(a,b);
    int nowa=deep[a]+tree.sum(idx[a]);
    int nowb=deep[b]+tree.sum(idx[b]);
    int nowl=deep[l]+tree.sum(idx[l]);
    return nowa+nowb-2*nowl;
}
void solve()
{
    tree.init();
    dfs_id(1,1,1);
    lca.init();
    merge_ret();
    for(int i=q;i>=1;i--)
    {
        if(query[i].op==1)
            merge(query[i].a,query[i].b);
        else
            query[i].ans=get_ans(query[i].a,query[i].b);
    }
    for1(i,q)if(query[i].ans!=-1)printf("%d\n",query[i].ans);
}
int main()
{
    int cas;
    read(cas);
    for1(tt,cas)
    {
        read(n,m,q);
        init();
        for1(i,m)
        {
            int a,b;read(a,b);
            vec[a].pb(edge(b));
            vec[b].pb(edge(a));
        }
        for1(i,n)sort(all(vec[i]));
        for1(i,q)query[i].READ();
        printf("Case #%d:\n", tt);
        solve();
    }
}