【题解】uoj236 【IOI2016】railroad(欧拉图+最小生成树)

这篇题解很好

总结:
特殊的哈密顿回路通常考虑转化成欧拉回路。
把NP问题转化成可解的东西
把速度看成点,一个很巧妙的转化!
这题利用了欧拉回路存在的充要条件每个联通块的进入和出去的边数相同,等价于所有点出入度相同。
然后要一次性走完,还要联通,因此要最小生成树。
离散化后unique一下就没有孤立点了。所有留下的点都要联通

#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x) for(register int i = head[x] ; i ; i = e[i].next)
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> pr;

const int maxn = 4e5 + 10;
const int inf = 1e9;

struct node{
	int x,y,w;
	bool operator < (node a)const{
		return w < a.w;
	}
}e[maxn];

int fa[maxn],num[maxn],a[maxn],cnt,m;
ll ans;

int getfa(int x){ return fa[x] == x ? x : fa[x] = getfa(fa[x]); }
inline void merge(int x,int y){
//	cout<<x<<" "<<y<<endl;
	int p = getfa(x) , q = getfa(y);
	if ( p != q ) fa[p] = q;
}
long long plan_roller_coaster(std::vector<int> s, std::vector<int> t){
	s.pb(inf) , t.pb(1);
	rvc(i,s) a[++cnt] = s[i] , a[++cnt] = t[i];
	sort(a + 1,a + cnt + 1);
	cnt = unique(a + 1,a + cnt + 1) - a - 1;
	rep(i,1,cnt) fa[i] = i;
	rvc(i,s){
		s[i] = lower_bound(a + 1,a + cnt + 1,s[i]) - a;
		t[i] = lower_bound(a + 1,a + cnt + 1,t[i]) - a;
		num[s[i]]++;
		num[t[i]]--;
		merge(s[i],t[i]);
	}
	rep(i,1,cnt){
		num[i] += num[i - 1];
	//	cout<<num[i]<<" ";
		if ( num[i] > 0 ) ans += (ll)num[i] * (a[i + 1] - a[i]) , merge(i,i + 1);
		else if ( num[i] < 0 ) merge(i,i + 1);
		else if ( i < cnt ) e[++m] = (node){i,i + 1,a[i + 1] - a[i]};
	}
//	cout<<ans<<endl;
	sort(e + 1,e + m + 1);
	rep(i,1,m){
		int x = e[i].x , y = e[i].y , w = e[i].w;
//		cout<<x<<" "<<y<<" "<<w<<endl;
		int p = getfa(x) , q = getfa(y);
		if ( p != q ) fa[p] = q , ans += w;
	}
	return ans;
}
int main() {
    freopen("input.txt","r",stdin);
    int n;
    assert(1 == scanf("%d", &n));
    int need_answer;
    assert(1 == scanf("%d", &need_answer));
    std::vector<int> s(n), t(n);
    for (int i = 0; i < n; ++i)
        assert(2 == scanf("%d%d", &s[i], &t[i]));
    long long ans = plan_roller_coaster(s, t);
    printf("%lld\n", ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值