旋转卡壳
题解:
大致就是先求出凸包
然后有一个性质就是我们枚举每条边
然后凸包上的点到边的距离是单峰函数(刚开始傻逼的写了点对点)
于是可以two-point-two
为什么是对的呢
因为对于最远点对
我们取一条平行于边的直线,那这条边到那个点的距离就是最远距离
所以这样就是对的
另外我发现求凸包的代码需要判重。。
不过网上好多代码都不判重。。这样有重复点的话是错的
代码:
#include <cstdio> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define rint register int #define IL inline #define ll long long #define rep(i,h,t) for (int i=h;i<=t;i++) #define dep(i,t,h) for (int i=t;i>=h;i--) const int N=4e5; struct point{ int a,b,r; bool operator ==(point o) { return a==o.a&&b==o.b; } IL void jsr() { r=atan2(b,a); } point operator -(point o) { return (point){a-o.a,b-o.b}; } point operator +(point o) { return (point){a+o.a,b+o.b}; } int operator *(point o) { return a*o.a+b*o.b; } int operator ^(point o) { return a*o.b-b*o.a; } }p[N],q[N]; struct line{ point a,b; }; IL int dis(point x,point y) { return (x.a-y.a)*(x.a-y.a)+(x.b-y.b)*(x.b-y.b); } int lenth(point x) { return x.a*x.a+x.b*x.b; } IL int dis(point x,point y,point z) { if ((y-x)*(z-x)<=0) return dis(x,z); if ((x-y)*(z-y)<=0) return dis(y,z); int l=1ll*((y-x)^(z-x))*((y-x)^(z-x))/lenth(y-x); return l; } IL bool cmp(point x,point y) { return x.a<y.a||(x.a==y.a&&x.b<y.b); } IL bool pd(line x,point y) { return (x.b^(y-x.a))<0; } int t,n; void push(point x) { while (1<t&&pd((line){q[t-1],q[t]-q[t-1]},x)) t--; q[++t]=x; } template<class T>void maxa(T &x,T y) {if (x<y)x=y;} int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); cin>>n; rep(i,1,n) { int x,y; cin>>x>>y; p[i]=(point){x,y}; p[i].jsr(); } sort(p+1,p+n+1,cmp); int m=0; rep(i,1,n) if (i==1||!(p[i]==p[i-1])) p[++m]=p[i]; n=m; t=1; q[0]=q[t]=p[1]; rep(i,2,n) push(p[i]); dep(i,n-1,1) push(p[i]); int k2=1; int ans=0; /* rep(i,1,t) { while (k2<t&&dis(q[i],q[k2+1])>dis(q[i],q[k2])) k2++; maxa(ans,dis(q[i],q[k2])); }*/ rep(i,t+1,2*t) q[i]=q[i-t]; rep(i,1,t) { while (k2<2*t&&dis(q[i],q[i+1],q[k2])<=dis(q[i],q[i+1],q[k2+1])) k2++; maxa(ans,dis(q[i],q[k2])); maxa(ans,dis(q[i+1],q[k2])); } printf("%d",ans); return 0; }