HDU 4631

来源:互联网 发布:2m数据测试仪 编辑:程序博客网 时间:2024/05/20 03:04

题意 : 平面上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;}
原创粉丝点击