Network POJ - 3694

点击打开链接

q次询问 每一次加一条边 问加完这条边之后还剩多少割边

可以想到 对于一个无向图 缩完点之后就是一棵树 且树上的边就是原图中的割边

对于每一次加边操作 如果两点不在一个连通分量之中 就会把两点之间的所有割边全部去掉 形成有一个新的连通分量 相当于修改新树图中的一条链 这个过程用树链剖分维护一下就好了

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct node1
{
    int v;
    int next;
    int flag;
};

struct node2
{
    int l;
    int r;
    int laz;
    int val;
};

node1 edge1[400010],edge2[400010];
node2 tree[400010];
int first1[100010],first2[100010],dfn[100010],low[100010],belong[100010],degree[100010];
int pre[100010],fa[100010],deep[100010],sum[100010],son[100010],top[100010],mp1[100010],mp2[100010],mp3[100010];
int n,m,num,cnt,ans;

void addedge(node1* edge,int* first,int u,int v)
{
    edge[num].v=v;
    edge[num].next=first[u];
    edge[num].flag=0;
    first[u]=num++;
    return;
}

void dfsI(int cur,int pre)
{
    int tmp,i,v;
    num++;
    dfn[cur]=num,low[cur]=num;
    tmp=0;
    for(i=first1[cur];i!=-1;i=edge1[i].next)
    {
        v=edge1[i].v;
        if(dfn[v]==0)
        {
            dfsI(v,cur);
            low[cur]=min(low[cur],low[v]);
            if(low[v]>dfn[cur])
            {
                edge1[i].flag=1;
                edge1[i^1].flag=1;
            }
        }
        else if(v==pre)
        {
            if(tmp>0) low[cur]=min(low[cur],dfn[v]);
            tmp++;
        }
        else
        {
            low[cur]=min(low[cur],dfn[v]);
        }
    }
    return;
}

void dfsII(int cur)
{
    int i,v;
    for(i=first1[cur];i!=-1;i=edge1[i].next)
    {
        v=edge1[i].v;
        if(!belong[v]&&!edge1[i].flag)
        {
            belong[v]=cnt;
            dfsII(v);
        }
    }
    return;
}

void tarjan()
{
    int i,u,v;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    num=0,ans=0;
    for(u=1;u<=n;u++)
    {
        if(!dfn[u])
        {
            dfsI(u,-1);
        }
    }
    memset(belong,0,sizeof(belong));
    cnt=0;
    for(u=1;u<=n;u++)
    {
        if(!belong[u])
        {
            cnt++;
            belong[u]=cnt;
            dfsII(u);
        }
    }
    /*
    printf("***%d***\n",cnt);
    for(i=1;i<=n;i++)
    {
        printf("%d ",belong[i]);
    }
    printf("\n");
    */
    ans=cnt-1;
    memset(first2,-1,sizeof(first2));
    num=0;
    for(u=1;u<=n;u++)
    {
        for(i=first1[u];i!=-1;i=edge1[i].next)
        {
            v=edge1[i].v;
            if(belong[u]!=belong[v])
            {
                addedge(edge2,first2,belong[u],belong[v]);
            }
        }
    }
    return;
}

void dfsIII(int cur)
{
    int i,v,w;
    sum[cur]=1,son[cur]=-1;
    for(i=first2[cur];i!=-1;i=edge2[i].next)
    {
        v=edge2[i].v;
        if(v!=fa[cur])
        {
            pre[v]=1,fa[v]=cur,deep[v]=deep[cur]+1;
            mp3[i/2+1]=v;
            dfsIII(v);
            sum[cur]+=sum[v];
            if(son[cur]==-1||sum[son[cur]]<sum[v])
            {
                son[cur]=v;
            }
        }
    }
    return;
}

void dfsIV(int cur,int tp)
{
    int i,v;
    num++;
    top[cur]=tp,mp1[cur]=num,mp2[num]=cur;
    if(son[cur]==-1) return;
    dfsIV(son[cur],tp);
    for(i=first2[cur];i!=-1;i=edge2[i].next)
    {
        v=edge2[i].v;
        if(v!=fa[cur]&&v!=son[cur])
        {
            dfsIV(v,v);
        }
    }
    return;
}

void pushup(int cur)
{
    tree[cur].val=tree[2*cur].val+tree[2*cur+1].val;
    return;
}

void pushdown(int cur)
{
    if(tree[cur].laz)
    {
        tree[2*cur].val=0;
        tree[2*cur].laz=1;
        tree[2*cur+1].val=0;
        tree[2*cur+1].laz=1;
        tree[cur].laz=0;
    }
    return;
}

void build(int l,int r,int cur)
{
    int m;
    tree[cur].l=l;
    tree[cur].r=r;
    tree[cur].laz=0;
    if(l==r)
    {
        tree[cur].val=1;
        return;
    }
    m=(l+r)/2;
    build(l,m,2*cur);
    build(m+1,r,2*cur+1);
    pushup(cur);
    return;
}

int query(int pl,int pr,int cur)
{
    int res;
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        return tree[cur].val;
    }
    pushdown(cur);
    res=0;
    if(pl<=tree[2*cur].r) res+=query(pl,pr,2*cur);
    if(pr>=tree[2*cur+1].l) res+=query(pl,pr,2*cur+1);
    return res;
}

void update(int pl,int pr,int cur)
{
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        tree[cur].val=0;
        tree[cur].laz=1;
        return;
    }
    pushdown(cur);
    if(pl<=tree[2*cur].r) update(pl,pr,2*cur);
    if(pr>=tree[2*cur+1].l) update(pl,pr,2*cur+1);
    pushup(cur);
    return;
}

int ask(int u,int v)
{
    int res;
    res=0;
    while(top[u]!=top[v])
    {
        if(deep[top[u]]<deep[top[v]]) swap(u,v);
        res+=query(mp1[top[u]],mp1[u],1);
        u=fa[top[u]];
    }
    if(u==v) return res;
    if(deep[u]<deep[v]) swap(u,v);
    res+=query(mp1[son[v]],mp1[u],1);
    return res;
}

void change(int u,int v)
{
    while(top[u]!=top[v])
    {
        if(deep[top[u]]<deep[top[v]]) swap(u,v);
        update(mp1[top[u]],mp1[u],1);
        u=fa[top[u]];
    }
    if(deep[u]<deep[v]) swap(u,v);
    update(mp1[v],mp1[u],1);
    return;
}

void solve()
{
    pre[1]=0,fa[1]=0,deep[1]=1;
    dfsIII(1);
    num=0;
    dfsIV(1,1);
    build(1,cnt,1);
    return;
}

int main()
{
    int cas,q,i,u,v;
    cas=1;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0) break;
        memset(first1,-1,sizeof(first1));
        num=0;
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            addedge(edge1,first1,u,v);
            addedge(edge1,first1,v,u);
        }
        tarjan();
        solve();
        printf("Case %d:\n",cas++);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d",&u,&v);
            if(belong[u]!=belong[v])
            {
                ans-=ask(belong[u],belong[v]);
                change(belong[u],belong[v]);
            }
            printf("%d\n",ans);
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/80529080