1. 程式人生 > >jzoj5895 【NOIP2018模擬10.5】旅遊 (求歐拉回路,性質)

jzoj5895 【NOIP2018模擬10.5】旅遊 (求歐拉回路,性質)

題目描述

在這裡插入圖片描述

分析

一個無向圖存在歐拉回路當且僅當所有的點的度數為偶數,所以需要在每一對奇點之間連一條邊然而觀察這題這題的邊權,發現所有比某條邊小的邊之和比這條邊小。那也就是說最短路必定在最小生成樹上。這就變成了最小生成樹上的配對問題。只要保證不走重邊,結果一定是一樣的。一棵子樹內假如是奇數那麼會有一個點需要走一次向外連的邊。

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