题解:P14234 [COI 2011] 河流 / RIJEKA

这边是题目传送门喵!

样例二可爱。我最初还以为是错题。后面修复了。

题意简述

对于一条长度为 \(m\) 的河流,你要划船从第 \(0\) 个点划到第 \(m\) 个点。在途中要送 \(n\) 个乘客,第 \(i\) 位乘客要从第 \(u\) 个点送到第 \(v\) 个点。最小化从第 \(0\) 个点划船到第 \(m\) 个点并运送所有乘客的行驶路程。

思路

首先,如果一个人都不用接,直接划船到终点即可,答案为 \(m\)

显然,就算要接乘客,也必须跑完这一段。因此容易看出,如果乘客正好与这一段顺路,显然就不会使答案增加。即当 \(u \leq v\) 时,这送一个乘客可以在必经的道路中顺便解决。

因此只用讨论 \(u > v\) 的情况。故记录每一段要往回送的区间的左右端点。

对于无交集的两区间,显然分别将乘客往回送即可,因为没有其他选择。

如上图所示。对于有交集的两区间,比如红色这一段和蓝色这一段,如果分别运送,会比紫色的路径多走中间这重复的一段。显然紫色的路径更优。

然后注意到往回走的话是一个来回,因此这一段要计算两次。

因此对所有区间取并集,所得集合长度的两倍加上 \(m\) 就是答案啦。

AC 代码:

#include<bits/stdc++.h>
#define ll long long
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=300005;
int n,m,cnt;
struct node {
	int l,r;
}a[N];

bool cmp(node p,node q) {
	if(p.l==q.l)return p.r<q.r;
	return p.l<q.l;
}

signed main() {
	ios;cin>>n>>m;
	int u,v;
	for(int i=1;i<=n;i++) {
		cin>>u>>v;
		if(u<=v)continue;//顺路即可直接顺着带走
		//u>v
		cnt++;
		a[cnt].l=v;
		a[cnt].r=u;
	}
	sort(a+1,a+1+cnt,cmp);
    int l=a[1].l;
    int r=a[1].r;
    ll ans=m;
    for(int i=2;i<=cnt;i++) {
        if(a[i].l<=r)r=max(r,a[i].r);//有交集,则将区间向右拓展
        else ans+=2*(r-l),l=a[i].l,r=a[i].r;//这一段结束了,开始新的区间且计算答案
    }
    ans+=2*(r-l);
    //更新最后的答案
	cout<<ans;
	return 0;
}

感谢阅读喵!

posted @ 2025-10-30 16:17  Circle_Table  阅读(1)  评论(0)    收藏  举报