#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6 + 5;
int n1, n2;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int n, i, j;
cin >> n;
int sum = 0;
vector<pair<int, int>> s, t;//动态分配内存,直接开1e6会MLE
s.push_back({-1e9, -1e9}), t.push_back({-1e9, -1e9});
vector<int> a(n + 1), b(n + 1);
for(i = 1; i <= n; i++){
cin >> a[i];
}
//画图后可以发现,设p[i] = {min(a[i], b[i]), max(a[i], b[i])}, p[i]看成一个区间,
//设a[i] < b[i]的为正区间,a[i] > b[i]的为逆区间,只有交换一个正区间和逆区间的a,
//|a - b|之和才会减小,减小的值为2 * 区间交集的长度
//把正区间放到s,逆区间放到t,问题转化为求s中区间和t中区间交集的最大值
for(i = 1; i <= n; i++){
cin >> b[i];
if(a[i] < b[i]) s.push_back({a[i], b[i]});
else if(a[i] > b[i]) t.push_back({b[i], a[i]});
sum += abs(a[i] - b[i]);
}
n1 = s.size() - 1, n2 = t.size() - 1;
sort(s.begin() + 1, s.end());//排序
sort(t.begin() + 1, t.end());
vector<int> pre_maxs(n1 + 5, -1e9), pre_maxt(n2 + 5, -1e9);
for(i = 1; i <= n1; i++){
pre_maxs[i] = max(pre_maxs[i - 1], s[i].second);//求前缀右端点的最大值
}
for(i = 1; i <= n2; i++){
pre_maxt[i] = max(pre_maxt[i - 1], t[i].second);
}
int maxx = 0;
for(i = 1; i <= n1; i++){
int pos = upper_bound(t.begin() + 1, t.end(), s[i]) - t.begin() - 1;
//对于s中的一个区间,在t中找到第一个左端点大于s[i]左端点的区间,那么t中该区间左边都是
左端点小于等于s[i]左端点的,取前缀右端点最大的一个区间
if(pos >= 1) maxx = max(maxx, min(s[i].second, pre_maxt[pos]) - s[i].first);
}
for(i = 1; i <= n2; i++){//因为上面for循环只考虑t[i].first <= s[i].firs的情况,所以对t
也重复一遍
int pos = upper_bound(s.begin() + 1, s.end(), t[i]) - s.begin() - 1;
if(pos >= 1) maxx = max(maxx, min(t[i].second, pre_maxs[pos]) - t[i].first);
}
cout << sum - 2 * maxx;
return 0;
}
求两个集合中区间交集最大值
最新推荐文章于 2025-12-19 15:31:04 发布
本文介绍了如何通过C++编程解决一个区间优化问题,通过交换正区间和逆区间来最小化绝对差值之和,利用排序和前缀最大值计算交集最大值。
2529

被折叠的 条评论
为什么被折叠?



