jzoj5895 【NOIP2018模擬10.5】旅遊 (求歐拉回路,性質)
阿新 • • 發佈:2018-12-02
題目描述
分析
一個無向圖存在歐拉回路當且僅當所有的點的度數為偶數,所以需要在每一對奇點之間連一條邊然而觀察這題這題的邊權,發現所有比某條邊小的邊之和比這條邊小。那也就是說最短路必定在最小生成樹上。這就變成了最小生成樹上的配對問題。只要保證不走重邊,結果一定是一樣的。一棵子樹內假如是奇數那麼會有一個點需要走一次向外連的邊。
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 5e5+10, mo = 998244353 ;
int n,m;
int final[N],nex[N*2],to[N*2],w[N*2],tot;
int f[N];
void link(int x,int y,int ww) {
to[++tot] = y,nex[tot] = final[x],final[x] = tot;
w[tot] = ww;
}
int s[N],fa[N];
ll ans,d[N];
int gf(int x) {return fa[x]==0?x:fa[x]=gf(fa[x]);}
void dfs(int x,int q) {
s[x] = (d[x]&1);
for (int i = final[x]; i; i=nex[i]) {
int y = to[i]; if (y != f[x]) {
f[y]=x;
dfs(y,w[i]);
s[x]+=s[y];
}
}
ans = (ans + (s[x]&1) * q) % mo;
}
int main() {
freopen("travel.in","r",stdin);
// freopen("travel.out","w",stdout);
cin>>n>>m;
tot = 1;
ll x = 1,zzz = 0;
for (int i = 1; i <= m; i++) {
x = x * 2 % mo;
zzz = (zzz + x) % mo;
int u,v; scanf("%d %d",&u,&v);
d[u]++,d[v]++;
if (gf(u)!=gf(v)) {
fa[gf(u)] = gf(v);
link(u,v,x);
link(v,u,x);
}
}
dfs(1,0);
cout<<(ans+zzz)%mo<<endl;
}