4814: [Cqoi2017]小Q的草稿

来源:互联网 发布:电影票网络代售商 编辑:程序博客网 时间:2024/06/05 16:43

4814: [Cqoi2017]小Q的草稿

Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 266 Solved: 46
[Submit][Status][Discuss]
Description

小Q是个程序员。众所周知,程序员在写程序的时候经常需要草稿纸。小Q现在需要一张草稿纸用来画图,但是桌上
只有一张草稿纸,而且是一张被用过很多次的草稿纸。草稿纸可以看作一个二维平面,小Q甚至已经给它建立了直
角坐标系。以前每一次草稿使用过的区域,都可以近似的看作一个平面上的一个三角形,这个三角形区域的内部和
边界都不能再使用。当然了,以前的草稿也没有出现区域重叠的情况。小Q已经在草稿纸上画上了一些关键点,这
些关键点都在没使用过的区域。小Q想把这些关键点两两之间尽可能的用线段连接起来。连接两个关键点的线段有
可能会穿过已经用过的草稿区域,这样显然不允许。于是小Q就想知道,有多少对关键点可以被线段连接起来,而
且还不会穿过已经用过的区域。为了方便,小Q保证任意三个关键点不会共线。
Input

第一行包含两个整数V,T,表示草稿纸上的关键点数量和三角形区域数量。
接下来V行,每行两个整数x,y,表示一个关键点的坐标(x,y)。
接下来T行,每行六个整数x1,y1,x2,y2,x3,y3,表示一个三角形区域的三个顶点坐标分别是(x1,y1),(x2,y2),(x3,y
3)保证三角形的面积大于0。
V<=1000,T<=1000,0<=所有坐标<=10^8且为整数
Output

输出一行,一个整数,表示能够被线段连接起来的关键点有多少对。
Sample Input

3 0

0 0

2 0

2 2
Sample Output

3

整个草稿纸是全新的,任意两个关键点都可以连线。
HINT

Source

[Submit][Status][Discuss]


显然需要O(n2)枚举每个点对,然后判断对答案是否有贡献
问题在于如何快速确定是否被三角形的边阻拦
枚举一个中心点o,将所有其他点都对它求一个极角
然后对于平面上的每一个三角形,拆成三条边
显然只需要拿出三条边中对点o限制得最紧的那个
这里的限制是在被覆盖的角度中任取一点,这个位置上这条边到o点的距离
这条边显然是两端点对于o张角最大的那个
那么每条边就处理成两个事件,在极角α处添加,在极角β处删除
对于任意的两条边,肯定是一个时间段一条边对o限制得比另一条边更紧些
而且时间段不会分裂成很多块
因为对于边A,如果在某个时刻限制得比B更紧了,那么直到它们中某一条被删除,这个情况是持续的
因为任意两个三角形不相交,也就等于任意两条边不相交
于是,对于当前未被删除的边集,显然可以拿出一个set来维护
注意set中的比较函数是动态的
总复杂度O(n2logn)

#include<iostream>  #include<cstring>  #include<cstdio>  #include<cmath>  #include<vector>#include<stack>  #include<algorithm>  #include<set>  #define min(a,b) ((a) < (b) ? (a) : (b))  using namespace std;  const int maxn = 1010;  typedef double DB;  const DB EPS = 1E-10;  const DB G = 1000;  typedef long long LL;  struct Point{      DB x,y; Point(){}      Point(DB x,DB y): x(x),y(y){}      Point operator * (const DB &t) {return Point(x * t,y * t);}      Point operator + (const Point &B) {return Point(x + B.x,y + B.y);}      Point operator - (const Point &B) {return Point(x - B.x,y - B.y);}  };  typedef Point Vector;  Point o,V[maxn],A[maxn],B[maxn];  inline DB Dot(Vector v1,Vector v2) {return v1.x * v2.x + v1.y * v2.y;}  inline DB Length(Vector v) {return sqrt(Dot(v,v));}  inline DB Cross(Vector v1,Vector v2) {return v1.x * v2.y - v2.x * v1.y;}  struct Line{      Point p; Vector v; Line(){}      Line(Point p,Vector v): p(p),v(v){}  }cur,L[maxn];  inline Point GetIntersection(Line L1,Line L2)  {      Vector u = L1.p - L2.p;      DB t = Cross(L2.v,u) / Cross(L1.v,L2.v);      return L1.p + L1.v * t;  }  struct Event{      Point p; DB ang; int typ,Num; Event(){}      Event(Point p,int typ,int Num): p(p),typ(typ),Num(Num){ang = atan2(p.y - o.y,p.x - o.x);}      bool operator < (const Event &B) const    {          return (fabs(ang - B.ang) <= EPS) ? typ < B.typ : ang < B.ang;    }  }D[maxn * 3];  int n,m,Ans,I;bool ins[maxn],vis[maxn];struct data{      int id; data(){}      data(int id): id(id){}      bool operator < (const data &B) const     {          Point P1 = GetIntersection(cur,L[id]);        Point P2 = GetIntersection(cur,L[B.id]);        return Length(P1 - o) < Length(P2 - o);    }  };  stack <int> stk;multiset <data> s;  multiset <data> :: iterator it[maxn];vector <Point> T[maxn];  inline DB Calc(Point A,Point B)  {      DB a = Length(A - B),b = Length(A - o),c = Length(B - o);      return (b * b + c * c - a * a) / (2.00 * b * c);  }  inline bool Check(DB a,DB b,DB c)  {      if (b > c) swap(b,c);      return fabs(a - b) <= EPS || fabs(a - c) <= EPS || (b < a && a < c);  }  inline bool InLine(Point p,Point p0,Point p1)  {      return Check(p.x,p0.x,p1.x) && Check(p.y,p0.y,p1.y);  }  inline void Work(Event e)  {      if (e.typ == 1)    {        cur = Line(o,e.p - o); ins[e.Num] = 1;        Point P1 = GetIntersection(cur,L[4]);        Point P2 = GetIntersection(cur,L[5]);        DB d1 = Length(P1 - o),d2 = Length(P2 - o);        it[e.Num] = s.insert(e.Num);    }     else if (e.typ == 3) s.erase(it[e.Num]),ins[e.Num] = 0;      else     {          if (!s.size()) {++Ans; return;}          int now = (*s.begin()).id;          Point P = GetIntersection(Line(o,e.p - o),L[now]);          if (!InLine(P,A[now],B[now]) || !InLine(P,o,e.p)) ++Ans;    }  }  inline void Solve(int k)  {      int tot = 0; o = V[k];      for (int i = 1; i < k; i++)          D[++tot] = Event(V[i],2,0);      for (int i = 1; i <= m; i++)      {          pair <DB,int> H[3];          for (int j = 0; j < 3; j++)              H[j] = make_pair(Calc(T[i][j],T[i][j + 1 == 3 ? 0 : j + 1]),j);          sort(H,H + 3); int x = H[0].second,y = x + 1 == 3 ? 0 : x + 1;          A[i] = T[i][x]; B[i] = T[i][y]; L[i] = Line(A[i],B[i] - A[i]);          if (Cross(A[i] - o,B[i] - o) < 0) swap(A[i],B[i]);          D[++tot] = Event(A[i],1,i); D[++tot] = Event(B[i],3,i);      }      int pos; sort(D + 1,D + tot + 1);      for (int i = 1; i <= tot; i++)        if (D[i].typ == 1) {pos = i; break;}    for (int i = pos; i <= tot; i++)        if (D[i].typ == 1) vis[D[i].Num] = 1;        else if (D[i].typ == 3 && !vis[D[i].Num]) stk.push(D[i].Num);    for (int i = 1; i < pos; i++)        if (D[i].typ == 1) vis[D[i].Num] = 1;        else if (D[i].typ == 3 && !vis[D[i].Num]) stk.push(D[i].Num);    Work(D[pos]); memset(vis,0,sizeof(vis));    while (!stk.empty())    {        int k = stk.top(); stk.pop();        it[k] = s.insert(k); ins[k] = 1;    }    for (int i = pos + 1; i <= tot; i++)        Work(D[i]);    for (int i = 1; i < pos; i++) Work(D[i]);    for (int i = 1; i <= m; i++)        if (ins[i]) s.erase(it[i]),ins[i] = 0;}  inline int getint()  {      char ch = getchar(); int ret = 0;      while (ch < '0' || '9' < ch) ch = getchar();      while ('0' <= ch && ch <= '9')          ret = ret * 10 + ch - '0',ch = getchar();      return ret;  }  int main()  {      #ifdef DMC          freopen("DMC.txt","r",stdin);      #endif      n = getint(); m = getint();    if (!m) {cout << n * (n - 1) / 2 << endl; return 0;}    for (int i = 1; i <= n; i++)      {          DB x = getint(),y = getint();          V[i] = Point(x / G,y / G);      }      for (int i = 1; i <= m; i++)          for (int j = 0; j < 3; j++)          {              DB x = getint(),y = getint();              T[i].push_back(Point(x / G,y / G));          }    for (I = 2; I <= n; I++) Solve(I);      cout << Ans << endl;      return 0;  }