hdu4496 D-City (并查集删边+离线)

题意描述:给你一个图,有n个点和m条边,然后询问你在删除1条边,2条边,.....m条边以后这个图里有几个连通分量。

分析:询问连通分量,很明显用并查集维护,稍微需要思考的是这个删边操作。熟悉并查集,我们都知道,两个点合并连通分量是很简单的,但是删除边就不能直接操作。

          这里我们应该想到逆序,考虑做完所有删边操作以后的图就是我们的初始的图,然后回推这个过程。然后就很容易想到把删改成添的过程,如果添加一条边图中少了一个连通分量,那么删这条边图中很明显就会多一个连通分量。因为要逆序,所以这是一个离线的算法。逆序过程可以用栈来维护。

           这题wa了一发,原因是写的是单组输入,改成多组输入立马AC。

#include<stdio.h>
#include<stack>
using namespace std;
const int maxn=1e5+5;

struct edge
{
    int u,v;

} e,tem;
int p[10005];

int findset(int x)
{
    return x==p[x]?p[x]:p[x]=findset(p[x]);

}
void join(int x,int y)
{
    int px=findset(x),py=findset(y);
    if(px!=py)
        p[py]=px;
}


int main()
{
    int n,m,a,b;
    while(~scanf("%d%d",&n,&m))
    {
        stack<edge>st;
        stack<int>ans;
        for(int i=0; i<n; i++)
            p[i]=i;
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&a,&b);
            e.u=a;
            e.v=b;
            st.push(e);
        }
        while(!st.empty())
        {
            tem=st.top();
            st.pop();
            if(findset(tem.u)!=findset(tem.v))
            {
                ans.push(n);
                n--;
            }
            else ans.push(n);
            join(tem.u,tem.v);
        }
        while(!ans.empty())
        {
            printf("%d\n",ans.top());
            ans.pop();
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zero___zero/article/details/81189850