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; }