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();
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值