2019.01.16【HDU5359】Group(SCC)(支配树)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/86513814

传送门


题意:

给出一个有向图,求出分别删掉每条边之后强连通分量数量是否变化。

解析:

我用三个小时的浪费证明了一件事:
stack的空间常数比vector不知道大了多少倍。。。

最后把stack换成vector就AC了???

卡常三小时,AC一秒钟。。。

去UOJ群里面问了一下,标准规定的stack底层容器是deque???

然后手动改成stack<int,vector<int> > 发现空间小的不是一点半点。。。

思路:

首先删掉连接强连通分量的边是不可能增加联通快数量的。

那么考虑对每个连通分量内单独处理。

显然我们需要找的边一定是某个点到其他点路上的必经边。

考虑化边为点建立支配树。

随便选择一个原图中的点当做根就能建立支配树了,显然我们只需要考虑两种情况:它到其他点的必经边,其他点到它的必经边。

其中第二种情况显然只需要在反图上面处理就行了,仍然处理它到其他点的必经边。

需要建立 n n 棵支配树?

不,每个连通分量建立一棵就行了,根节点可以任意选择一个原图中的节点。

这么做的理由也很简单,如果一条边的删除会导致连通分量的增加,那么支配树必然会被它分成两部分,而我们随意选择的根必然在其中一个部分,所以怎么选择根都会把需要删除的边计算进来。

当然代码就十分的不忍直视了。。。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define cs const

namespace IO{
    namespace IOONLY{
        cs int Rlen=1<<20|1;
        char buf[Rlen],*p1,*p2;
        char obuf[Rlen],*p3=obuf;
        char ch[23];
    }
    inline char get_char(){
        using namespace IOONLY;
        return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
    }
    inline void put_char(char c){
        using namespace IOONLY;
        *p3++=c;
        if(p3==obuf+Rlen)fwrite(obuf,1,Rlen,stdout),p3=obuf;
    }
    inline void FLUSH(){
        using namespace IOONLY;
        fwrite(obuf,1,p3-obuf,stdout),p3=obuf;
    }
    
    inline int getint(){
        re int num;
        re char c;
        while(!isdigit(c=gc()));num=c^48;
        while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
        return num;
    }
}
using namespace IO;

cs int N=300005;
namespace DT{
    int n,st;
    struct Graph{
        vector<int> edge[N];
        inline void clear(){for(int re i=1;i<=n;++i)edge[i].clear();}
        inline void addedge(int u,int v){edge[u].push_back(v);}
    }g,revg;
	vector<int> dom[N];
    
    int dfn[N],fa[N],id[N],dfs_clock;
    void dfs(int u){
        id[dfn[u]=++dfs_clock]=u;
        for(int re e=0,v;e<g.edge[u].size();++e){
            v=g.edge[u][e];
            if(dfn[v])continue;
            fa[v]=u;dfs(v);
        }
    }
    
    int bel[N],val[N],semi[N],idom[N];
    
    inline int getfa(int x){
        if(bel[x]==x)return x;
        int tmp=getfa(bel[x]);
        if(dfn[semi[val[bel[x]]]]<dfn[semi[val[x]]])val[x]=val[bel[x]];
        return bel[x]=tmp;
    }
    
    int du[N];
    
    inline void tarjan(){
        for(int re i=dfs_clock,u;i>1;--i){
            u=id[i];
            for(int re e=0,v;e<revg.edge[u].size();++e){
                v=revg.edge[u][e];
                if(!dfn[v])continue;
                getfa(v);
                if(dfn[semi[val[v]]]<dfn[semi[u]])semi[u]=semi[val[v]];
            }
            dom[semi[u]].push_back(u);
            u=bel[u]=fa[u];
            for(int re i=0;i<dom[u].size();++i){
                int v=dom[u][i];
                getfa(v);
                if(semi[val[v]]==u)idom[v]=u;
                else idom[v]=val[v];
            }
            dom[u].clear();
        }
        for(int re i=2;i<=dfs_clock;++i){
            int u=id[i];
            if(semi[u]^idom[u])idom[u]=idom[idom[u]];
            ++du[idom[u]];
        }
    }
    
    inline void init(){
        g.clear(),revg.clear();
        for(int re i=1;i<=n;++i)semi[i]=bel[i]=val[i]=i,dfn[i]=0,du[i]=0;
        dfs_clock=0;
    }
    
    inline void init(cs int &_n,cs vector<pair<int,int> > &edge,cs int &_st){
        n=_n;st=_st;
        init();
        for(int re i=0;i<edge.size();++i){
            int u=edge[i].first,v=edge[i].second;
            g.addedge(u,v);
            revg.addedge(v,u);
        }
    }
    
    inline void build(){
        dfs(st);
        tarjan();
    }
    
    inline bool isleaf(int u){return !du[u];}
}

int n,m;
vector<int> edge[N];
inline void addedge(int u,int v){edge[u].push_back(v);}

int dfn[N],low[N],dfs_clock;
int scc[N],scc_clock;
bool ok[N];
vector<int> sta;
bool inst[N];

int pos[N],id[N],cnt;

void tarjan(int u){
    dfn[u]=low[u]=++dfs_clock;
    sta.push_back(u);
    inst[u]=true;
    for(int re e=0,v;e<edge[u].size();++e){
        v=edge[u][e];
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(inst[v])low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        ++scc_clock;
        cnt=0;int st=0;
        while(true){
            int x=sta.back();sta.pop_back();
            scc[x]=scc_clock;
            pos[id[x]=++cnt]=x;
            inst[x]=false;
            if(x<=n&&!st)st=id[x];
            if(x==u)break;
        }
        
        if(cnt==1)return ;
        vector<pair<int,int> >edges;
        
        for(int re i=1,u;i<=cnt;++i){
            u=pos[i];
            for(int re e=0,v;e<edge[u].size();++e){
                v=edge[u][e];
                if(scc[v]^scc_clock)continue;
                edges.push_back(make_pair(id[v],id[u]));
            }
        }
        DT::init(cnt,edges,st);
        DT::build();
        for(int re i=1;i<=cnt;++i){
            if(DT::isleaf(i))continue;
            int u=pos[i];
            if(u>n)ok[u-n]=true;
        }
        
        edges.clear();
        for(int re i=1,u;i<=cnt;++i){
            u=pos[i];
            for(int re e=0,v;e<edge[u].size();++e){
                v=edge[u][e];
                if(scc[v]^scc_clock)continue;
                edges.push_back(make_pair(id[u],id[v]));
            }
        }
        DT::init(cnt,edges,st);
        DT::build();
        for(int re i=1;i<=cnt;++i){
            if(DT::isleaf(i))continue;
            int u=pos[i];
            if(u>n)ok[u-n]=true;
        }
    }
}

inline void init(){
    for(int re i=1;i<=n+m;++i){
        edge[i].clear();
        dfn[i]=scc[i]=ok[i]=0;
    }
    dfs_clock=scc_clock=0;
}

inline void solve(){
    n=getint(),m=getint();
    for(int re i=1;i<=m;++i){
        int u=getint(),v=getint();
        addedge(u,i+n);
        addedge(i+n,v);
    }
    for(int re i=1;i<=n+m;++i){
        if(!dfn[i])tarjan(i);
    }
    for(int re i=1;i<=m;++i){
        pc(ok[i]?'1':'0');
    }
    pc('\n');
}

signed main(){
    for(int T=getint();T--;)init(),solve();
    FLUSH();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/86513814