標籤:二分 同方向判斷
題意:給了一個凸包,按順時針順序給點,點數不超過10萬,再給了兩個不同點,點嚴格在凸包內,凸包保證沒有三點共線,問凸包上有多少對點(pi, pj),滿足pi和pj的線段 與 兩個點的線段嚴格相交,線段間嚴格相交意思是交點不在端點。
連結:http://codeforces.com/gym/100517 (K題)
解法:設凸包有n個點,將凸包點集p擴大一倍,變為2n個點。枚舉前n個點,每次枚舉到 i ,在[i+1, i+n-1]內進行二分,找到兩個點p1,p2,滿足p1和p2是”最靠近” 那兩點線段 的點。統計下中間個數即可。二分過程中需要進行一種同方向判斷,即判斷該直線是否在某一個線段”左邊”或”右邊”,用叉積判斷即可。
代碼
//Hello. I‘m Peter.//#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<iostream>#include<sstream>#include<cstring>#include<string>#include<cmath>#include<cstdlib>#include<algorithm>#include<functional>#include<cctype>#include<ctime>#include<stack>#include<queue>#include<vector>#include<set>#include<map>using namespace std;typedef long long ll;inline int read(){ int x=0,f=1;char ch=getchar(); while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f;}const double eps = 1e-9, pi = acos(-1.0);inline int sgn(double x){ if(fabs(x) < eps) return 0; else return x > 0? 1 : -1;}struct Point{ double x, y; Point(){}; Point(double x1, double y1){x = x1, y = y1;}};typedef Point Vector;Vector operator + (const Vector a, const Vector b){return Vector(a.x + b.x, a.y + b.y);}Vector operator - (const Vector a, const Vector b){return Vector(a.x - b.x, a.y - b.y);}double operator * (const Vector a, const Vector b){return a.x * b.x + a.y * b.y;}double operator % (const Vector a, const Vector b){return a.x * b.y - a.y * b.x;}Vector operator * (const Vector a, const double b){return Vector(a.x * b, a.y * b);}Vector operator * (const double b, const Vector a){return Vector(a.x * b, a.y * b);}Vector operator / (const Vector a, const double b){return Vector(a.x / b, a.y / b);}bool operator == (const Point a, const Point b){return sgn(a.x - b.x)==0 && sgn(a.y - b.y)==0;}bool operator || (const Vector a, const Vector b){return sgn(a % b)==0;}bool operator / (const Vector a, const Vector b){return sgn(a % b)!=0;}double Length(Vector v){return (double)sqrt((double)(v.x * v.x + v.y * v.y));}double Dis(Point a, Point b){return Length(a - b);}Vector Rotate(Vector v, double rad){return Vector(v.x * cos(rad) - v.y * sin(rad), v.x * sin(rad) + v.y * cos(rad));}double angle(Vector v){return atan2(v.y, v.x);}double angle(Vector a, Vector b){ double ans = angle(a) - angle(b); while(sgn(ans) < 0) ans += 2*pi; while(sgn(ans) >= 2*pi) ans -= 2*pi; return fmin(ans, 2*pi - ans);}double Area_Tri(Point p1, Point p2, Point p3){return 0.5 * fabs((p2 - p1) % (p3 - p1));}double Area_Tri(double a, double b, double c){double p = (a+b+c)/2; return (double)sqrt((double)(p*(p-a)*(p-b)*(p-c)));}struct Line{ Point p; Vector v; Line(){}; Line(Point p1, Vector v1){p = p1, v = v1;}};Point operator / (const Line a, const Line b){ double t = ((b.p - a.p) % b.v) / (a.v % b.v); return a.p + a.v * t;}double Dis(Point p, Line l){return fabs(l.v % (p - l.p)) / Length(l.v);}double angle(Line a, Line b){double ans = angle(a.v, b.v); return fmin(ans, pi - ans);}struct Seg{ Point p1, p2; Seg(){}; Seg(Point p11, Point p22){p1 = p11, p2 = p22;}};bool operator / (const Seg a, const Seg b){//need change return sgn((a.p2 - a.p1) % (b.p1 - a.p1)) * sgn((a.p2 - a.p1) % (b.p2 - a.p1)) <= 0 && sgn((b.p2 - b.p1) % (a.p1 - b.p1)) * sgn((b.p2 - b.p1) % (a.p2 - b.p1)) <= 0 ;}bool operator / (const Line a, const Seg b){ return sgn(a.v % (b.p1 - a.p)) * sgn(a.v % (b.p2 - a.p)) <= 0;}bool PointOnSeg(Point p, Seg s){ if((s.p1 - p) / (s.p2 - p)) return false; else if(sgn((s.p1 - p) * (s.p2 - p)) > 0) return false; else return true;}#define N 200010int n;Point p[N];Point p1 , p2;Point readPoi(){ int x, y; x = read(), y = read(); return Point(x, y);}void kuoda(){ for(int i = n + 1; i <= n + n; i++){ p[i] = p[i - n]; }}void solve(){ ll ans = 0; for(int i = 1; i <= n; i++){ int l ,r , mid; l = i + 1, r = i + n - 1; Vector v1 = p1 - p[i], v2 = p2 - p[i]; while(l < r){ mid = (l + r) >> 1; Vector v = p[mid] - p[i]; if(sgn(v % v1) <= 0 && sgn(v % v2) <= 0) r = mid; else l = mid + 1; } int tp1 = l; l = i + 1, r = i + n - 1; while(l < r){ mid = (l + r) >> 1; mid++; Vector v = p[mid] - p[i]; if(sgn(v % v1) >= 0 && sgn(v % v2) >= 0) l = mid; else r = mid - 1; } int tp2 = l; if(tp1 != tp2) ans += tp1 - tp2 - 1; } ans >>= 1; cout<<ans<<endl;}int main(){ freopen("kingdom.in","r",stdin); freopen("kingdom.out","w",stdout); while(~scanf("%d",&n) && n > 0){ for(int i = 1; i <= n; i++) p[i] = readPoi(); p1 = readPoi(); p2 = readPoi(); kuoda(); solve(); } return 0;}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Codeforces gym 100517(二分,同方向判斷)