LA4728 Squares
阿新 • • 發佈:2018-12-23
題意
分析
就是求凸包點集的直徑。
當然選擇旋轉卡殼。
然後是實現上的技巧:
當Area(p[u], p[u+1], p[v+1]) <= Area(p[u], p[u+1], p[v])時停止旋轉
即Cross(p[u+1]-p[u], p[v+1]-p[u]) - Cross(p[u+1]-p[u], p[v]-p[u]) <= 0
根據Cross(A,B) - Cross(A,C) = Cross(A,B-C)
化簡得Cross(p[u+1]-p[u], p[v+1]-p[v]) <= 0
畫個圖就能發現,這樣找的是對於一條邊三角形的最大高。為什麼這樣是對的呢?
凸包上一個點到其他點的距離是一個凸函式。然後在兩條直線慢慢旋轉的過程中,可以考慮直接轉一條邊,這樣求出的是到這條直線的最大距離,顯然就是對踵點對。
實現的時候初始化可以直接暴力轉,因為均攤是\(O(n)\)的。
時間複雜度\(O(T n \log n)\)。
程式碼
由於座標都是整數,而又不涉及需要實數運算的操作,所以Point
類可以直接實現為整數座標。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<set> #include<map> #include<queue> #include<stack> #include<algorithm> #include<bitset> #include<cassert> #include<ctime> #include<cstring> #define rg register #define il inline #define co const template<class T>il T read() { rg T data=0; rg int w=1; rg char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') w=-1; ch=getchar(); } while(isdigit(ch)) { data=data*10+ch-'0'; ch=getchar(); } return data*w; } template<class T>T read(T&x) { return x=read<T>(); } using namespace std; typedef long long ll; struct Point { int x,y; Point(int x=0,int y=0) :x(x),y(y){} bool operator<(co Point&rhs)co { return x<rhs.x||(x==rhs.x&&y<rhs.y); } bool operator==(co Point&rhs)co { return x==rhs.x&&y==rhs.y; } }; typedef Point Vector; Vector operator-(co Point&A,co Point&B) { return Vector(A.x-B.x,A.y-B.y); } int Cross(co Vector&A,co Vector&B) { return A.x*B.y-A.y*B.x; } int Dot(co Vector&A,co Vector&B) { return A.x*B.x+A.y*B.y; } int Dist2(co Vector&A,co Vector&B) { return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y); } vector<Point>ConvexHull(vector<Point>&p) { sort(p.begin(),p.end()); p.erase(unique(p.begin(),p.end()),p.end()); int n=p.size(); int m=0; vector<Point>ch(n+1); for(int i=0;i<n;++i) { while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) --m; ch[m++]=p[i]; } int k=m; for(int i=n-2;i>=0;--i) { while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) --m; ch[m++]=p[i]; } if(n>1) --m; ch.resize(m); return ch; } int Diameter2(vector<Point>&points) { vector<Point>p=ConvexHull(points); int n=p.size(); if(n==1) return 0; if(n==2) return Dist2(p[0],p[1]); p.push_back(p[0]); // avoid % int ans=0; for(int u=0,v=1;u<n;++u) { for(;;) { int diff=Cross(p[u+1]-p[u],p[v+1]-p[v]); if(diff<=0) { ans=max(ans,Dist2(p[u],p[v])); if(diff==0) ans=max(ans,Dist2(p[u],p[v+1])); break; } v=(v+1)%n; } } return ans; } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); int T=read<int>(); while(T--) { int n=read<int>(); vector<Point>points; for(int i=0;i<n;++i) { int x=read<int>(),y=read<int>(),w=read<int>(); points.push_back(Point(x,y)); points.push_back(Point(x+w,y)); points.push_back(Point(x,y+w)); points.push_back(Point(x+w,y+w)); } printf("%d\n",Diameter2(points)); } return 0; }