jzoj 5895.【NOIP2018模擬10.5】旅遊 最小生成樹
阿新 • • 發佈:2018-12-13
Description
Input
Output
Sample Input
6 10
4 6
4 5
3 6
5 2
3 2
1 2
3 4
6 1
2 4
1 3
Sample Output
2132
Data Constraint
分析:
顯然至少每條邊走一次,在這基礎上,所有的奇點都要走一條路徑到另外一個奇點。相當於把奇點兩兩配對,配對代價是他們的最短路,然後我就不會了。
最後發現兩點的最短路一定在最小生成樹上。因為第條邊代價為,所以兩個點走前面的路徑能連通,那麼最短路就確定了。
於是我們相當於在最小生成樹上,有一些奇點,兩兩配對的最小代價,直接貪心即可。
程式碼:
#include <iostream> #include <cmath> #include <cstdio> const int maxn=5e5+7; const int mod=998244353; using namespace std; int n,m,power,ans,cnt,x,y; int ls[maxn],p[maxn],r[maxn],sum[maxn]; struct edge{ int y,w,next; }g[maxn*2]; int find(int x) { if (!p[x]) return x; return p[x]=find(p[x]); } void uni(int x,int y) { int u=find(x),v=find(y); if (u==v) return; p[u]=v; } int dfs(int x,int fa) { sum[x]=r[x]; for (int i=ls[x];i>0;i=g[i].next) { int y=g[i].y; if (y==fa) continue; dfs(y,x); sum[x]+=sum[y]; if (sum[y]%2) ans=(ans+g[i].w)%mod; } } void add(int x,int y,int w) { g[++cnt]=(edge){y,w,ls[x]}; ls[x]=cnt; } int main() { freopen("travel.in","r",stdin); freopen("travel.out","w",stdout); scanf("%d%d",&n,&m); power=1; for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); power=(power*2)%mod; if (find(x)!=find(y)) { add(x,y,power); add(y,x,power); uni(x,y); } r[x]++; r[y]++; ans=(ans+power)%mod; } dfs(1,0); printf("%d",ans); }