HDU 5458 Stability 树链剖分

题意:给n个点m条边的无向图,图中可能包含自环和重边,现在有两种操作:
1.删掉一条(a,b)边
2.询问a->b上有多少条关键边,关键边意思为:删掉该边,使得a不能到达b。
所有删除操作都保证图是连通的。

把删除操作倒着加边来搞。
先随便建一颗树,边权为1,若加边(a,b),那么a到b的路径上的边权都赋值为0
询问a b则为a->b的边权和。用树链来搞。

//author: CHC
//First Edit Time: 2015-09-21 23:32
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=1e+4 * 3 + 1000;
const int MAXM=1e+5 * 2 + 1000;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();
struct Edge {
    int to,next;
    Edge(){}
    Edge(int _to,int _next):to(_to),next(_next){}
    bool operator<(const Edge &x) const {
        if(to!=x.to)return to<x.to;
        return next<x.next;
    }
}e[MAXM];
int head[MAXN],tot;
int path[MAXN];
int Find(int x){
    int tx=x;
    while(tx!=path[tx])tx=path[tx];
    while(x!=path[x]){
        int t=path[x];
        path[x]=tx;
        x=t;
    }
    return tx;
    //return x==path[x]?x:path[x]=Find(path[x]);
}
bool Union(int x,int y){
    x=Find(x),y=Find(y);
    if(x==y)return false;
    path[x]=y;
    return true;
}
multiset <Edge> S,V;
multiset <Edge> ::iterator it,it1;
void init(){
    memset(head,-1,sizeof(head));
    tot=0;
    S.clear();V.clear();
    for(int i=1;i<MAXN;i++)path[i]=i;
}
void AddEdge(int u,int v){
    e[tot]=Edge(v,head[u]);
    head[u]=tot++;
    e[tot]=Edge(u,head[v]);
    head[v]=tot++;
}
int dep[MAXN],son[MAXN],siz[MAXN],fa[MAXN],prew[MAXN];
int tim,id[MAXN],rid[MAXN],top[MAXN];
void dfs1(int u,int father,int w){
    fa[u]=father;siz[u]=1;son[u]=-1;
    prew[u]=w;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v!=father){
            dep[v]=dep[u]+1;
            dfs1(v,u,1);
            siz[u]+=siz[v];
            if(son[u]==-1||siz[v]>siz[son[u]])son[u]=v;
        }
    }
}
void dfs2(int u,int tp){
    top[u]=tp; id[u]=++tim; rid[tim]=u;
    if(son[u]==-1)return ;
    dfs2(son[u],tp);
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])dfs2(v,v);
    }
}
#define lson L,mid,rt<<1
#define rson mid+1,R,rt<<1|1
struct Tree {
    int ans,flag;
}tr[MAXN<<2];
void pushup(int rt){
    tr[rt].ans=tr[rt<<1].ans+tr[rt<<1|1].ans;
}
void pushdown(int rt){
    if(tr[rt].flag){
        tr[rt<<1].ans=tr[rt<<1|1].ans=0;
        tr[rt<<1].flag=tr[rt<<1|1].flag=1;
        tr[rt].flag=0;
    }
}
void build(int L,int R,int rt){
    tr[rt].flag=0;
    if(L==R){
        tr[rt].ans=prew[rid[L]];
        tr[rt].flag=0;
        return ;
    }
    int mid=(L+R)>>1;
    build(lson);build(rson);
    pushup(rt);
}
void update(int L,int R,int rt,int l,int r){
    if(tr[rt].ans==0)return ;
    if(l<=L&&R<=r){
        tr[rt].ans=0;
        tr[rt].flag=1;
        return ;
    }
    pushdown(rt);
    int mid=(L+R)>>1;
    if(l<=mid)update(lson,l,r);
    if(r>mid)update(rson,l,r);
    pushup(rt);
}
int query(int L,int R,int rt,int l,int r){
    if(tr[rt].ans==0)return 0;
    if(l<=L&&R<=r)return tr[rt].ans;
    pushdown(rt);
    int mid=(L+R)>>1,ans=0;
    if(l<=mid)ans+=query(lson,l,r);
    if(r>mid)ans+=query(rson,l,r);
    pushup(rt);
    return ans;
}
void updatex(int a,int b,int n){
    while(top[a]!=top[b]){
        if(dep[top[a]]<dep[top[b]])swap(a,b);
        update(1,n,1,id[top[a]],id[a]);
        a=fa[top[a]];
    }
    if(a==b)return ;
    if(dep[a]>dep[b])swap(a,b);
    update(1,n,1,id[son[a]],id[b]);
}
int queryx(int a,int b,int n){
    int ans=0;
    while(top[a]!=top[b]){
        if(dep[top[a]]<dep[top[b]])swap(a,b);
        ans+=query(1,n,1,id[top[a]],id[a]);
        a=fa[top[a]];
    }
    if(a==b)return ans;
    if(dep[a]>dep[b])swap(a,b);
    ans+=query(1,n,1,id[son[a]],id[b]);
    return ans;
}
struct Q {
    int type,a,b;
    void init(){
        scanf("%d%d%d",&type,&a,&b);
    }
}cs[MAXN*10];
int ans[MAXN*10];
int main()
{
    int T,n,m,q,cas=0;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&m,&q);
        init();
        for(int i=0,x,y;i<m;i++){
            scanf("%d%d",&x,&y);
            if(x>y)swap(x,y);
            S.insert(Edge(x,y));
        }
        //puts("here");
        for(int i=0;i<q;i++){
            cs[i].init();
            if(cs[i].type==1){
                if(cs[i].a>cs[i].b)swap(cs[i].a,cs[i].b);
                it=S.lower_bound(Edge(cs[i].a,cs[i].b));
                S.erase(it);
            }
        }
        //puts("here");
        for(it=S.begin();it!=S.end();it++){
            if(Union(it->to,it->next)){
                V.insert(*it);
                AddEdge(it->to,it->next);
            }
        }
        //puts("here3");

        for(it=V.begin();it!=V.end();it++){
            it1=S.lower_bound(*it);
            S.erase(it1);
        }

        //puts("here");
        dep[1]=0;
        tim=0;
        dfs1(1,1,0);
        dfs2(1,1);
        build(1,n,1);
        for(it=S.begin();it!=S.end();it++){
            updatex(it->next,it->to,n);
        }
        for(int i=q-1;i>=0;i--){
            if(cs[i].type==1){
                updatex(cs[i].a,cs[i].b,n);
            }
            else {
                ans[i]=queryx(cs[i].a,cs[i].b,n);
            }
        }
        printf("Case #%d:\n",++cas);
        for(int i=0;i<q;i++)
            if(cs[i].type==2)printf("%d\n",ans[i]);
    }
    return 0;
}

你可能感兴趣的:(树链剖分)