70pts,wa#4#7#8
只wa在最长点对,旋转卡壳的板子题过了
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <queue>
#define ll long long
#define db double
using namespace std;
const db EPS = 1e-10;
const db INF = 1e40;
const ll N = 1e5 + 100;
// 浮点数加法处理
db add(db va, db vb) {
if (abs(va + vb) < EPS * (abs(va) + abs(vb))) {
return 0;
}
return va + vb;
}
// 平方
db sq(db val) {
return val * val;
}
// 点、向量结构体
struct P {
db x,y;
P() {};
P(db x, db y) : x(x) , y(y) {
}
// 四则运算
P operator + (P const &p) const {
return P(add(x,p.x),add(y,p.y));
}
P operator - (P const &p) const {
return P(add(x,-p.x),add(y,-p.y));
}
P operator * (db const &d) const {
return P(x * d, y * d);
}
P operator / (db const &d) const {
return P(x / d, y / d);
}
bool operator < (P const &p) const {
if (x == p.x) {
return y < p.y;
}
return x < p.x;
}
// 点积
db dot(P p) {
return add(x * p.x, y * p.y);
}
// 叉积
db det(P p) {
return add(x * p.y, -y * p.x);
}
// 模长平方
db modl() {
return sq(x) + sq(y);
}
};
// 两点之间的距离
db disPnt(P px, P py) {
return sqrt(sq(py.x - px.x) + sq(py.y - px.y));
}
// 递归求平面最小点对(确认没有问题)
db closeDis(ll l, ll r, P * arr) {
if (r - l < 1) {
return INF;
}
ll mid = (l + r) >> 1;
db val = arr[mid].x;
db dis = min(closeDis(l,mid,arr),closeDis(mid + 1,r,arr));
sort(arr + l,arr + r + 1,[] (P const &px, P const &py) {
return px.y < py.y;
});
vector<P> b;
for (ll i = l;i <= r;i++) {
if (abs(arr[i].x - val) > dis) {
continue;
}
for (ll j = b.size() - 1;j >= 0;j--) {
if (arr[i].y - b[j].y > dis) {
break;
}
dis = min(dis,disPnt(arr[i],b[j]));
}
b.push_back(arr[i]);
}
return dis;
}
// 多边形结构体,本质是点集
struct Poly {
vector<P> pSet;
Poly() {};
Poly(vector<P> const &pSet) : pSet(pSet) {
}
// 生成凸包,Andrew算法
void conGene() {
// 取出点集长度
ll len = pSet.size();
// 把最下最左的点放在第一个
for (ll i = 1;i < len;i++) {
if (pSet[i].y - pSet[0].y < -EPS) {
swap(pSet[0],pSet[i]);
} else {
if ((abs(pSet[i].y - pSet[0].y) < EPS) && (pSet[i].x - pSet[0].x < -EPS)) {
swap(pSet[0],pSet[i]);
}
}
}
// 极角排序
sort(pSet.begin() + 1,pSet.end(),[&](const P &px, const P &py) {
P vx = px - pSet[0];
P vy = py - pSet[0];
// 极角相同按照距离第一个点的距离从小到大排序
if (abs(vx.det(vy)) < EPS) {
return (vy.modl() - vx.modl() < EPS);
} else {
return (vx.det(vy) > EPS);
}
});
// 构建栈
vector<P> stk;
// 算法核心
for (ll i = 0;i < len;i++) {
if (stk.empty()) {
stk.push_back(pSet[i]);
} else {
ll top = stk.size() - 1;
while(top > 0) {
P vx = stk[top] - stk[top - 1];
P vy = pSet[i] - stk[top - 1];
if (vx.det(vy) < -EPS) {
stk.pop_back();
top--;
} else {
break;
}
}
stk.push_back(pSet[i]);
}
}
pSet.clear();
// 将生成后的凸多边形赋给点集
swap(pSet, stk);
}
// 求凸包直径,旋转卡壳
db diaCon() {
ll len = pSet.size();
db res = 0.0;
// 活动指针
ll pt = 2 % len;
for (ll i = 0;i < len;i++) {
// 该边的长度与res比较
res = max(res,disPnt(pSet[i],pSet[(i + 1) % len]));
// 构建边向量,方便求面积
P vec = pSet[(i + 1) % len] - pSet[i];
// 活动指针的下一个指针
ll nxt = (pt + 1) % len;
// 如果nxt点与边构成的三角形面积大于pt点与边构成的三角形面积,则指针++
while(fabs(vec.det(pSet[nxt] - pSet[i])) - fabs(vec.det(pSet[pt] - pSet[i])) > 0) {
pt = nxt;
nxt = (nxt + 1) % len;
}
// 计算点对长度
res = max(res,max(disPnt(pSet[i],pSet[pt]),disPnt(pSet[(i + 1) % len],pSet[pt])));
}
return res;
}
};
ll tt,n;
// 使用该数组求平面最小点对
P pnt[N];
void solve() {
scanf("%lld",&n);
// 使用该数组求平面最大点对
vector<P> pnts;
for (ll i = 1;i <= n;i++) {
db x,y;
scanf("%lf%lf",&x,&y);
pnt[i] = P(x,y);
pnts.push_back(pnt[i]);
}
// 求最小点对前先按照x排序
sort(pnt + 1,pnt + n + 1);
db ansmn = closeDis(1,n,pnt);
// 构建多边形
Poly poly = Poly(pnts);
// 生成凸包
poly.conGene();
// 求凸包直径
db ansmx = poly.diaCon();
printf("%.12lf %.12lf",ansmn,ansmx);
}
int main() {
tt = 1;
while(tt) {
solve();
tt--;
}
return 0;
}