题意 : 平面上n个点依次加入,然后让你不断求任何两个点的最小距离。
题解 : 看到这个题目我们不难想到求平面上的最近点对的做法 先将加入的所有点的x按照从小到大排序, 每次向两边扫描x距离小于 当前最小值的所有点,不断更新当前最小值,直到出现0就停止这种操作,关键是怎样每次都保证x有序呢 ? 当然是不断加入 multiset 中 (因为点可以重复). 我们不难发现这样可以剪枝剪掉大量无用的点,但是如果所有的x 都是同一个的话,肯定就会达到最坏复杂度,但是这个题目的数据显然是随机出现的点,所以这种情况不可能出现,所以这种算法大概的复杂度也就很低,也可以认为不是水过去的吧 当然 kd tree 也是可以的
#include <cstdio>
#include <set>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 500000 + 10;
const long long INF = (1LL<<60);
int n, x[maxn], y[maxn];
struct Point{
int x;
int y;
bool operator < (const Point& e) const{
return x < e.x;
}
};
void read(int *a){
int A, B, C, i;
a[0] = 0;
scanf("%d%d%d", &A, &B, &C);
for(i = 1; i <= n; i++){
a[i] = ((long long)a[i-1] * A + B) % C;
}
}
long long solve(){
int i;
long long Min = INF, ret = 0;
multiset <Point> se;
se.clear();
Point v;
v.x = x[1];
v.y = y[1];
se.insert(v);
for(i = 2; i <= n; i++){
v.x = x[i];
v.y = y[i];
multiset<Point>::iterator p = se.lower_bound(v), iter;
for(iter = p; iter != se.end(); iter++){ //从p开始,一直到se.end()前一个位置
long long dx = v.x - iter->x;
dx *= dx;
if(dx >= Min) break; //剪枝
long long dy = v.y - iter->y;
dy *= dy;
Min = min(Min, dx + dy);
}
for(iter = p; iter != se.begin();){ //从p的上一个位置开始,一直算完se.begin()
iter --;
long long dx = v.x - iter->x;
dx *= dx;
if(dx >= Min) break; //剪枝
long long dy = v.y - iter->y;
dy *= dy;
Min = min(Min, dx + dy);
}
ret += Min;
se.insert(v);
}
return ret;
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
read(x);
read(y);
printf("%lld\n", solve());
}
return 0;
}