【UOJ#236】[IOI2016]railroad(欧拉回路,最小生成树)
题面
题解
把速度看成点,给定的路段看成边,那么现在就有了若干边,然后现在要补上若干边,以及一条([inf,)使得原图存在欧拉回路,那么就变成了求从大往小连边的边长的最小值。
而欧拉回路每个点被来回覆盖的次数左右一定是一样的,假设向右-向左覆盖的次数为(g_i),那么如果(g_i>0),花费(1)的代价向(i-1)连边,如果(g_i>0),那么则可以不花费代价连边(i
ightarrow i+1)。
看起来这样子得到了一个解,实际上欧拉回路还需要满足连通性,再求一遍(MST)把图连通就行了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include"railroad.h"
using namespace std;
#define MAX 400200
#define ll long long
int S[MAX<<2],top,cnt,c[MAX];
int f[MAX];int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
struct Line{int u,v,w;}e[MAX];
bool operator<(Line a,Line b){return a.w<b.w;}
long long plan_roller_coaster(vector<int> s,vector<int> t)
{
int n=s.size();ll ans=0;
for(int i=0;i<n;++i)S[++top]=s[i],S[++top]=t[i];
S[++top]=-1e9-100;S[++top]=1e9+100;
sort(&S[1],&S[top+1]);top=unique(&S[1],&S[top+1])-S-1;
for(int &i:s)i=lower_bound(&S[1],&S[top+1],i)-S;
for(int &i:t)i=lower_bound(&S[1],&S[top+1],i)-S;
c[2]=-1;c[top]=1;for(int i=1;i<=top;++i)f[i]=i;
for(int i=0;i<n;++i)c[s[i]+1]++,c[t[i]+1]--;
for(int i=0;i<n;++i)f[getf(s[i])]=getf(t[i]);
for(int i=1;i<=top;++i)c[i]+=c[i-1];
for(int i=2;i<=top;++i)
{
if(c[i]==0)continue;
if(c[i]>0)ans+=1ll*c[i]*(S[i]-S[i-1]);
f[getf(i)]=getf(i-1);
}
for(int i=2;i<top-1;++i)if(getf(i)!=getf(i+1))e[++cnt]=(Line){i,i+1,S[i+1]-S[i]};
sort(&e[1],&e[cnt+1]);
for(int i=1;i<=cnt;++i)
if(getf(e[i].u)!=getf(e[i].v))
f[getf(e[i].u)]=getf(e[i].v),ans+=e[i].w;
return ans;
}