http://www.elijahqi.win/archives/3603
题意翻译
定义无向图中简单环为某几条边构成的最小环(即该环中不再包含更小的环),现给出n点m条边(n,m<=100000),求恰好被包含在一个(多了少了都不行)简单环中的边,第一行输出这些边个数,第二行根据输入顺序输出这些边编号.数据保证无重边自环,但不一定保证连通.
感谢 @cy1366371760 提供的翻译。
以前一直写点入栈的点双 这次yy一下边入栈 wa不停..
考虑把所有点双搞出来 然后判断每个点双是不是简单环如果是简单环统计答案即可
如果这个点双不是简单环 那么所有的边一定都包含在两个环
直接判断点数是否和边数相同即可
边入栈的时候需要特判时间戳 来判断该边i是否需要入栈
#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
return x*f;
}
const int N=1e5+10;
struct node{
int y,next,id;
}data[N<<1];
struct node1{
int x,y,id;
}q[N];
int top,n,m,num,ans[N],h[N],dfn[N],low[N],size[N],s,b[N];vector<int> eg[N];
inline void tarjan(int x,int fa){
dfn[x]=low[x]=++num;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (y==fa) continue;
if (dfn[y]&&(dfn[y]<dfn[x]))q[++top]=(node1){x,y,data[i].id};
if (!dfn[y]){
q[++top]=(node1){x,y,data[i].id};
tarjan(y,x);low[x]=min(low[x],low[y]);
if (low[y]>=dfn[x]){
++s;node1 now;
while(1){
now=q[top--];eg[s].push_back(now.id);
if (b[now.x]!=s) ++size[s],b[now.x]=s;
if (b[now.y]!=s) ++size[s],b[now.y]=s;
if (now.x==x&&now.y==y) break;
}
}
}else low[x]=min(low[x],dfn[y]);
}
}
int main(){
freopen("cf962f.in","r",stdin);
n=read();m=read();
for (int i=1;i<=m;++i){
int x=read(),y=read();
data[++num].y=y;data[num].next=h[x];h[x]=num;data[num].id=i;
data[++num].y=x;data[num].next=h[y];h[y]=num;data[num].id=i;
}num=0;
for (int i=1;i<=n;++i) if (!dfn[i]) tarjan(i,i);top=0;
for (int i=1;i<=s;++i)
if(eg[i].size()==size[i])
for (int j=0;j<eg[i].size();++j) ans[++top]=eg[i][j];
sort(ans+1,ans+top+1);printf("%d\n",top);
for (int i=1;i<=top;++i) printf("%d ",ans[i]);
return 0;
}