图论好题啊!
首先我们枚举终点 \(u\),看到一定要走完指定的 \(m\) 条边,很像一条欧拉路问题啊!但是现在问题是一个欧拉路问题,有两个点的度数是奇数,并不好做。我们不妨先从起点 \(s\) 向 \(u\) 连一条边,变成欧拉回路问题。现在我们需要做的是将度数为奇数的点加边使其变为偶数。方法是将连续两个度数为奇数的点,中间的任意相邻两点连上一条度数为 \(1\) 的边。因为这样不但连通了更多的节点,代价还和直接连接两点的代价相同,肯定更优。
现在我们的图变成了若干个连通块了,想要使得图连通,我们需要在连通块之间找一条边,让它变成一张连通图,实际上就是一个最小生成树。我们先将连通块缩点,拿相邻的两个点连边,跑一个最小生成树即可。时间复杂度 \(O(n^2 \log n+m)\)。
点击查看代码
#include<bits/stdc++.h>#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()
#define inn(i,n,a) For(i,1,n) a[i]=read();#define ll long long
#define i128 __int128using namespace std;
inline int read() {int xx= 0;int f= 1;char c = getchar();while(c<'0'||c>'9') { if(c=='-') f= -1;c= getchar();}while(c>='0'&&c<='9') {xx= (xx<<1)+(xx<<3)+(c^48);c= getchar();}return xx*f;
}
#define maxn 200050
int n,m,st;
int deg[maxn];
int res;
int fa[maxn],bel[maxn];
struct node {int u,v,d;bool operator<(const node x) {return d<x.d; }
};
int find(int x) {return x==fa[x]?fa[x]:fa[x]=find(fa[x]); }
signed main() {in3(n,m,st);For(i,1,n) fa[i]=i;For(i,1,m) {int u,v;in2(u,v);deg[u]++,deg[v]++;res+=abs(u-v);fa[find(u)]=find(v);}For(i,1,n) bel[i]=find(i);//先缩一次点For(u,1,n) {deg[st]++,deg[u]++;For(i,1,n) fa[i]=i;fa[find(st)]=find(u);int ans=res,lst=0;For(i,1,n) if(deg[i]%2==1) {if(lst) {ans+=i-lst; For(j,lst,i) fa[find(bel[j])]=find(bel[i]); lst=0; }else lst=i;}vector<node>G; lst=0;For(i,1,n) if(deg[i]>0) { if(lst&&find(bel[lst])!=find(bel[i])) G.push_back({bel[lst],bel[i],abs(i-lst)});lst=i;}sort(G.begin(),G.end());for(auto [x,y,z]:G) if(find(x)!=find(y)) fa[find(x)]=find(y),ans+=2*z;cout<<ans<<' ';deg[u]--,deg[st]--;}
}