引理:
将一个区间$[l,r]$移动至点$x$ (区间将点覆盖)的距离是$(abs(l - x) + abs(r - x) - (r - l)) / 2$。
(即区间两端点分别到$x$的距离减去区间长度再除以2)
在该题中发现$X$方向的移动和$Y$方向无关,因此可以将$X$轴和$Y$轴独立来看。
以$X$方向为例:设最终共享的点是$x$,$X$方向上的每段区间记录在$range$中,那么最终需要移动的距离应该是:$$\sum_{i=1}^{n} (abs(range[i].l - x) + abs(range[i].r - x) - (r - l)) / 2$$
不难发现其中$(r - l)$是定值,即区间长度,因此目标就是要是最小化$abs(range[i].l - x) + abs(range[i].r - x)$,显然这可以用绝对值不等式求得最优值。
#include <iostream>
#include <cstring>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#define bug1(g) cout<<"test: "<<g<<endl
#define bug2(g , i) cout<<"test: "<<g<<" "<<i<<endl
#define bug3(g , i , k) cout<<"test: "<<g<<" "<<i<<" "<<k<<endl
#define bug4(a , g , i , k) cout<<"test: "<<a<<" "<<g<<" "<<i<<" "<<k<<endl
#define INF 0x3f3f3f3f
#define fi first
#define se second
#define met(a , b) memset(a , b , sizeof a);
#define pb push_back
using namespace std;
typedef long long LL ;
typedef pair<int , int> PII;
const int N = 1000010;
int n , a[N * 2];
PII x[N] , y[N];
LL work(PII t[])
{
for(int i = 0 ; i < n ; i++)
a[i] = t[i].fi , a[i + n] = t[i].se;
sort(a , a + n * 2);
LL res = 0;
for(int i = 0 ; i < n ; i++)
res += (abs(a[n] - t[i].fi) + abs(a[n] - t[i].se) - (t[i].se - t[i].fi)) / 2;
return res;
}
void solve()
{
cin >> n;
for(int i = 0 ; i < n ; i++)
{
int a , b , c , d;
scanf("%d%d%d%d" , &a , &b , &c , &d);
x[i] = {a , c} , y[i] = {b , d};
}
printf("%lld\n" , work(x) + work(y));
}
int main()
{
int T = 1;
cin >> T;
for(int turn = 1 ; turn <= T ; turn++)
solve();
}
这个就类似于货舱选址
是的,就是把点换成区间