http://acm.hdu.edu.cn/showproblem.php?pid=6736
找出所有环,每个环至少选择一条边删掉,那么方案数就是2^size-1,不在环上的边为m条,可以随便删,方案数就是2^resm。
点双抄一遍就过了,也可以直接dfs
#include<bits/stdc++.h>
#define maxl 500010
using namespace std;
const int mod=998244353;
int n,m,top,cnt,ind,sum,rt,dcccnt;
vector <int> dcc[maxl];
long long ans;
int dfn[maxl],low[maxl],ehead[maxl],s[maxl];
long long num[maxl];
bool in[maxl],cut[maxl];
struct ed
{
int to,nxt;
}e[maxl<<1];
inline void add(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
inline void tarjan(int u)
{
dfn[u]=low[u]=++ind;s[++top]=u;
if(u==rt && ehead[u]==0)
{
dcc[++dcccnt].push_back(u);
return;
}
int son=0,v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
son++;
if(u!=rt || son>1)
cut[u]=true;
dcccnt++;
int d;
do
{
d=s[top--];
dcc[dcccnt].push_back(d);
}while(d!=v);
dcc[dcccnt].push_back(u);
}
}
else
low[u]=min(low[u],dfn[v]);
}
}
inline void prework()
{
for(int i=1;i<=dcccnt;i++)
dcc[i].clear();
dcccnt=0;
for(int i=1;i<=n;i++)
{
dfn[i]=low[i]=0;in[i]=false;
ehead[i]=0;cut[i]=false;
}
int u,v;cnt=1;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
ind=0;
for(int i=1;i<=n;i++)
if(dfn[i]==0)
{
rt=i;top=0;
tarjan(i);
}
}
inline void mainwork()
{
int resm=m;
ans=1;
for(int i=1;i<=dcccnt;i++)
{
sum=dcc[i].size();
if(sum>=3)
ans=ans*num[sum]%mod,resm-=sum;
}
ans=ans*(num[resm]+1)%mod;
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
//freopen("1006.in","r",stdin);
num[0]=1;
for(int i=1;i<maxl;i++)
num[i]=2ll*num[i-1]%mod;
for(int i=0;i<maxl;i++)
num[i]=((num[i]-1)%mod+mod)%mod;
while(~scanf("%d%d",&n,&m))
{
prework();
mainwork();
print();
}
return 0;
}