虛樹DP。
#include<bits/stdc++.h>
#define maxn 100050
#define mod 998244353
#define pb push_back
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;
int n,m,sx[maxn],ty[maxn],ont[maxn],vis[maxn],ar[maxn],sb[maxn];
vector<int>G[maxn];
struct node{
int v,c[2][2];
};
vector<node>E[maxn];
int F[maxn],fa[maxn],f[maxn][2],cot[maxn],nf[maxn][2];
int Find(int u){ return !F[u] ? u : F[u] = Find(F[u]); }
void addtree(int x){
if(!ont[x]) ar[++ar[0]] = x;
ont[x] = 1;
for(;x && !vis[x];x=fa[x])
vis[x] = 1;
if(x){
if(!ont[x]) ar[++ar[0]] = x;
ont[x] = 1;
}
}
void dfs0(int u,int ff){
fa[u] = ff;
for(int v:G[u]) if(v^ff)
dfs0(v,u);
}
void dfs1(int u,int ff){
f[u][0] = 1 , f[u][1] = 1;
for(int v:G[u]) if(v^ff){
dfs1(v,u);
f[u][0] = 1ll * f[u][0] * (f[v][0] + f[v][1]) % mod;
f[u][1] = 1ll * f[u][1] * f[v][0] % mod;
}
}
void dfs2(int u,int ff){
cot[u] = ont[u];
for(int v:G[u])
if(v^ff)
dfs2(v,u),cot[u] += cot[v];
}
void dfs3(int u,int ff){
nf[u][0] = 1 , nf[u][1] = 1;
for(int v:G[u]) if(v^ff && cot[v] == 0){
dfs3(v,u);
nf[u][0] = 1ll * nf[u][0] * (nf[v][0] + nf[v][1]) % mod;
nf[u][1] = 1ll * nf[u][1] * nf[v][0] % mod;
}
}
int banc[maxn][2],pf[maxn][2];
void dfs5(int u){
pf[u][0] = nf[u][0];
pf[u][1] = nf[u][1];
for(auto v:E[u]){
dfs5(v.v);
pf[u][0] = 1ll * pf[u][0] * (1ll * v.c[0][0] * pf[v.v][0] % mod + 1ll * v.c[0][1] * pf[v.v][1] % mod ) % mod;
pf[u][1] = 1ll * pf[u][1] * (1ll * v.c[1][0] * pf[v.v][0] % mod + 1ll * v.c[1][1] * pf[v.v][1] % mod ) % mod;
}
// printf("@%d %d %d\n",u,pf[u][0],pf[u][1]);
if(banc[u][0]) pf[u][0] = 0;
if(banc[u][1]) pf[u][1] = 0;
}
int ans ;
void dfs4(int u){
if(u == m-n+2){
dfs5(1);
ans = (ans + 1ll * pf[1][0] + pf[1][1] ) % mod;
return;
}
banc[sb[u<<1]][1]++;
dfs4(u+1);
banc[sb[u<<1]][1]--;
banc[sb[u<<1]][0]++;
banc[sb[u<<1|1]][1]++;
dfs4(u+1);
banc[sb[u<<1]][0]--;
banc[sb[u<<1|1]][1]--;
}
int main(){
scanf("%d%d",&n,&m);
sb[++sb[0]] = 1;
rep(i,1,m){
scanf("%d%d",&sx[i],&ty[i]);
if(Find(sx[i]) ^ Find(ty[i])){
G[sx[i]].pb(ty[i]);
G[ty[i]].pb(sx[i]);
F[Find(sx[i])] = Find(ty[i]);
}
else{
sb[++sb[0]] = sx[i],sb[++sb[0]] = ty[i];
}
}
dfs0(1,0);
rep(i,1,sb[0]) addtree(sb[i]);
rep(i,1,ar[0]){
if(ar[i] == 1) continue;
int j=fa[ar[i]],pr=ar[i];
f[pr][0] = 1 , f[pr][1] = 0;
for(;!ont[j];j=fa[j],pr=fa[pr]){
f[j][0] = f[j][1] = 1;
for(int v:G[j]) if(v^fa[j]){
if(v^pr) dfs1(v,j);
f[j][0] = 1ll * f[j][0] * (f[v][0] + f[v][1]) % mod;
f[j][1] = 1ll * f[j][1] * f[v][0] % mod;
}
}
node p;p.v = ar[i],p.c[0][0]=(f[pr][0]+f[pr][1])%mod,p.c[1][0]=f[pr][0];
j=fa[ar[i]],pr=ar[i];
f[pr][0] = 0 , f[pr][1] = 1;
for(;!ont[j];j=fa[j],pr=fa[pr]){
f[j][0] = f[j][1] = 1;
for(int v:G[j]) if(v^fa[j]){
if(v^pr) dfs1(v,j);
f[j][0] = 1ll * f[j][0] * (f[v][0] + f[v][1]) % mod;
f[j][1] = 1ll * f[j][1] * f[v][0] % mod;
}
}
p.c[0][1]=(f[pr][0]+f[pr][1])%mod,p.c[1][1]=f[pr][0];
E[j].pb(p);
}
dfs2(1,0);
rep(i,1,ar[0])
dfs3(ar[i],fa[ar[i]]);
dfs4(1);
printf("%d\n",(ans+mod)%mod);
}