【bzoj4064】[Cerc2012]The Dragon and the knights

  1A真是excited(雾
  似乎这题就是个乱搞吧
  所有的直线不重合不共点,那么每加一条直线,总的区域数就加上这条直线和之前多少条直线相交再加1。如果把在同一个区域内的点看做一个点集,则就是判断点集的个数是否等于总的区域数。
  于是重点就转成了判断有哪些点在同一个区域内,换句话说,在同一个区域内的点,都是在某些直线的同侧。注意到这点就好办了,如果把每个点都和原点连一条线段,则每个点在直线的方位,就是直线和这个点与原点构成的线段是否有交点。对于每个点都把交点的状态哈希一下然后统计不同数即可。
  但是要注意到一个问题,如果直线过了原点,似乎就有一点点复杂。有一个很好的替代方案,就是选择平面上任意一个不在任意一条直线上的点作为线段的另外一端。这样就可以在一定程度上避免一些讨论。
  时间复杂度 O(mn+mlogm)
  咦为什么会带log呢?(雾
  啊……还有……又忘记不能加time(0)了 T_T
  其实是交了两次才A的= =
  

#include 
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define shl(x) (1ull << (x))
#define pii pair
#define mp make_pair
#define maxn 107
#define maxm 50003

inline int rd() {
    char c = getchar() ;
    while (!isdigit(c) && c != '-') c = getchar();
    int x = 0 , f = 1;
    if (c == '-') f = -1 ; else x = c - '0';
    while (isdigit(c = getchar())) x = x * 10 + c - '0';
    return x * f;
}

template<class T>inline void upmax(T&a , T b) { if (a < b) a = b ; }

typedef unsigned long long ull;

typedef int arr_int[maxm];
typedef double arr_db[maxm];

const double eps = 1e-4;

arr_db A , B , C , X , Y;
pii h[maxm];
int tot , n , m;
int mx;

inline int rnd() {
    return (rand() << 16) | rand();
}

int fcmp(double a , double b) {
    if (fabs(a - b) <= eps) return -1;
    if (a < b - eps) return 0;
    return 1;
}

bool banana(int i , int j) {
    return fcmp(A[i] * B[j] , A[j] * B[i]) != -1;
}

double f(int i , double x , double y) {
    return A[i] * x + B[i] * y + C[i];
}

bool on_line(double x , double y) {
    rep (i , 1 , n)
        if (fcmp(f(i , x , y) , 0) == -1)
            return 1;
    return 0;
}

bool seg_banana(int i , int x1 , int y1 , int x2 , int y2) {
    if (!banana(0 , i)) return 0;
    return f(i , x1 , y1) * f(i , x2 , y2) <= eps;
}

void input() {
    n = rd() , m = rd() , mx = 0;
    tot = n + 1;
    rep (i , 1 , n) {
        A[i] = rd() , B[i] = rd() , C[i] = rd();
        rep (j , 1 , i - 1) if (banana(i , j))
            tot ++;
    }
    rep (i , 1 , m) X[i] = rd() , Y[i] = rd() , upmax(mx , (int) max(abs(X[i]) , abs(Y[i])));
}

void solve() {
    double x = rnd() , y = rnd();
    while (on_line(x , y)) x = rnd() % mx , y = rnd() % mx;
    rep (i , 1 , m) {
        h[i] = mp(0 , 0);
        A[0] = Y[i] - y , B[0] = x - X[i] , C[0] = X[i] * y - x * Y[i];
        rep (j , 1 , n) if (seg_banana(j , x , y , X[i] , Y[i])) {
            if (j >= 50) h[i].first |= shl(j - 50);
            else h[i].second |= shl(j - 1);
        }
    }
    sort(h + 1 , h + m + 1);
    int t = unique(h + 1 , h + m + 1) - h - 1;
    puts(t >= tot ? "PROTECTED" : "VULNERABLE");
}

int main() {
    per (T , rd() , 1) {
        input();
        solve();
    }
    return 0;
}

你可能感兴趣的:(计算几何)