Description
Solution
本来晕乎乎的看到可怜就瞬间清醒了
其实我们可以通过加边使得条件由每条边走至少一次变成每条边走恰好一次。
注意到给出的边非常特殊,可以发现所有有贡献的边都在最小生成树上。如果n很小也可以考虑传递闭包做
考虑怎么加边,我们发现每次加边会使两端点度数的奇偶性发生变化。由于我们添加的实际上是一条路径,那么我们可以考虑一条边在路径中的贡献。如果一条边两边的奇点的数量都是奇数,那么这条边一定会算入答案
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
typedef long long LL;
const LL INF=1000000000000000;
const int MOD=998244353;
const int N=500005;
struct edge {int y,w,next;} e[N*2];
LL bin[N],ans;
int d[N],ls[N],fa[N],g[N],edCnt;
void add_edge(int x,int y,int w) {
e[++edCnt]=(edge) {y,w,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,w,ls[y]}; ls[y]=edCnt;
}
int find(int x) {
if (!fa[x]) return x;
return fa[x]=find(fa[x]);
}
void dfs(int now,int from) {
g[now]=d[now]&1;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==from) continue;
dfs(e[i].y,now);
if (g[e[i].y]) ans=(ans+e[i].w)%MOD;
g[now]^=g[e[i].y];
}
}
int main(void) {
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
int n,m; scanf("%d%d",&n,&m);
bin[0]=1; rep(i,1,m) bin[i]=bin[i-1]*2LL%MOD;
rep(i,1,m) {
int x,y; scanf("%d%d",&x,&y);
++d[x]; ++d[y];
if (find(x)!=find(y)) {
add_edge(x,y,bin[i]);
fa[find(x)]=find(y);
}
ans=(ans+bin[i])%MOD;
}
dfs(1,0);
printf("%lld\n", ans);
return 0;
}