1. 程式人生 > >jzoj5895 旅遊 最小生成樹+歐拉回路

jzoj5895 旅遊 最小生成樹+歐拉回路

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