[CF962F]Simple Cycles Edges

题目

传送门

题解

首先应分析在什么情况下,一条边才只会包含在一个简单环里面。

如果两个环有公共边,对于这两个环的边分情况讨论:

  • 对于公共边,这条边被左、右俩环同时包含,显然不符题意;
  • 对于非公共边,首先他们分别属于自己的环,其次,他们又在一个最外围的大环上;

也就是说,如果两个环有公共边,那么这俩环上没有边是符合题意的。

那么我们的目的就很明确了——寻找独立的简单环的边数并输出其编号。

此处“独立”是指与其他环没有公共边。

那么,问题变成如何“寻找”独立环,分析独立环的特性——显然,点数等于边数,这是再显然不过的条件。

那么,我们可以将图中的点双全部找出来,对于每一个点双再分别判断点数是否等于边数即可。

为什么不找边双?显然两个简单环是可以存在公共点的(区分公共边),所以我们寻找的其实是割点而非桥,最简单的一个模型就是 \(8\) 字结构,在这种模型下边双就会出问题(CF 的数据应该是 test#8)。

代码

#include<cstdio>
#include<set>
using namespace std;

#define rep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i>=i##_end_;--i)
#define erep(i,u) for(signed i=tail[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
typedef long long LL;
// typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef unsigned uint;
#define Endl putchar('\n')
// #define int long long
// #define int unsigned
// #define int unsigned long long

#define cg (c=getchar())
template<class T>inline void read(T& x){
    char c;bool f=0;
    while(cg<'0'||'9'<c)f|=(c=='-');
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    if(f)x=-x;
}
template<class T>inline T read(const T sample){
    T x=0;char c;bool f=0;
    while(cg<'0'||'9'<c)f|=(c=='-');
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    return f?-x:x;
}
template<class T>void fwrit(const T x){//just short,int and long long
    if(x<0)return (void)(putchar('-'),fwrit(-x));
    if(x>9)fwrit(x/10);
    putchar(x%10^48);
}
template<class T>inline T Max(const T x,const T y){return x<y?y:x;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
    inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
    return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}

const int maxn=100000;
const int maxm=100000;

struct edge{int to,nxt;}e[maxm*2+5];
int tail[maxn+5],ecnt=1;//从 1 开始
inline void add_edge(const int u,const int v){
    e[++ecnt]=edge{v,tail[u]};tail[u]=ecnt;
    e[++ecnt]=edge{u,tail[v]};tail[v]=ecnt;
}

int n,m;

inline void Init(){
    n=read(1),m=read(1);
    rep(i,1,m)add_edge(read(1),read(1));
}

int stk[maxn*3+5],st;
int dfn[maxn+5],low[maxn+5],idx;

int dcc_cnt;
set<int>nde[maxn+5],ege[maxn+5];

void tarjan(const int u,const int pre){
    dfn[u]=low[u]=++idx;
    erep(i,u)if(v^pre){
        if(!dfn[v]){
            stk[++st]=i>>1,stk[++st]=u,stk[++st]=v;
            tarjan(v,u);
            low[u]=Min(low[u],low[v]);
            if(low[v]>=dfn[u]){
                ++dcc_cnt;
                int n1,n2;
                while(1){
                    nde[dcc_cnt].insert(n1=stk[st--]);
                    nde[dcc_cnt].insert(n2=stk[st--]);
                    ege[dcc_cnt].insert(stk[st--]);
                    if(n1==v && n2==u)break;
                }
            }
        }else if(dfn[v]<dfn[u]){
            stk[++st]=i>>1,stk[++st]=u,stk[++st]=v;
            low[u]=Min(low[u],dfn[v]);
        }
    }
}

set<int>ans;

signed main(){
    Init();
    rep(i,1,n)if(!dfn[i])tarjan(i,0);
    rep(i,1,dcc_cnt)if(nde[i].size()==ege[i].size())
        ans.insert(ege[i].begin(),ege[i].end());
    writc(ans.size(),'\n');
    for(int u:ans)writc(u,' ');
    return 0;
}
posted @ 2020-08-21 11:35  Arextre  阅读(136)  评论(0编辑  收藏  举报