[cnblogs] [hdu6163]CSGO

多校第9场第3题,一场比赛3个计算几何,甘版下风。

讲道理,看到题就知道是要转一圈,题目也规定了线段之间无相交,这也意味着以同一个点为中心,线段之间的遮挡关系是不变的,我们就可以通过维护当前角度上最近的线段,来判断某个点是否能被击中。

维护遮挡关系,可以直接比较他们与当前角度的射线的交点,到原点的距离,这里用了一些奇怪的方法来获得这个距离(这个方法只有在确定与射线有交点后才是正确的。

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<queue>
#include<set>
#include<ctime>
#include<map>
 
using namespace std;
 
typedef long long ll;
typedef unsigned long long ull;
 
typedef long double ld;
 
const ld eps = 1e-20;
ld PI = acos((ld)-1.0);
 
//#define ENABLE_FREAD
 
struct io_s {
 
    bool negative;
    char ch;
 
    inline bool isdigitx(char c) {
        return c >= '0' && c <= '9';
    }
 
 
#ifdef ENABLE_FREAD
    inline char nextchar() {
        static char buf[100000], *p1 = buf, *p2 = buf;
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
    }
#else
    inline char nextchar() {
        return getchar();
    }
#endif
 
    template<typename T>
    bool rn(T& _v) {
        negative = false;
        _v = 0;
        while (!isdigitx(ch = nextchar()) && ch != EOF) { negative = ch == '-'; };
        if (ch == EOF)return false;
        do {
            _v *= 10;
            _v += ch - '0';
        } while (isdigitx(ch = nextchar()));
        if (negative) _v = -_v;
        return true;
    }
 
    template<typename T>
    bool run(T& _v) {
        _v = 0;
        while (!isdigitx(ch = nextchar()) && ch != EOF) {};
        if (ch == EOF)return false;
        do {
            _v *= 10;
            _v += ch - '0';
        } while (isdigitx(ch = nextchar()));
        return true;
    }
 
    template<typename T>
    inline T r() {
        T v = T();
        rn(v);
        return v;
    }
 
    inline int ri() { return r<int>(); }
    inline ll rll() { return r<ll>(); }
 
    inline int gets(char* s) {
        return gets(s, '\0');
        /*
        char* c = s;
        do {
        ch = nextchar();
        } while (ch == '\n' || ch == '\r');
        do {
        *(c++) = ch;
        ch = nextchar();
        } while (ch != '\n' && ch != '\r');
        *(c++) = '\0';
        return c - s - 1;
        */
    }
 
    inline int gets(char* s, char base) {
        char* c = s;
        do {
            ch = nextchar();
        } while (ch == '\n' || ch == '\r');
        do {
            *(c++) = ch - base;
            ch = nextchar();
        } while (ch != '\n' && ch != '\r');
        *(c++) = '\0';
        return c - s - 1;
    }
 
    inline char get() {
        do {
            ch = nextchar();
        } while (ch <'A' || ch >'Z');
        return ch;
    }
 
    template<class T>
    inline void o(T p) {
        static int stk[70], tp;
        if (p == 0) { putchar('0'); return; }
        if (p < 0) { p = -p; putchar('-'); }
        while (p) stk[++tp] = p % 10, p /= 10;
        while (tp) putchar(stk[tp--] + '0');
    }
    inline void ln() { putchar('\n'); }
 
    inline void space() { putchar(' '); }
 
    template<class T>
    inline void oln(T p) {
        o(p); ln();
    }
 
} io;
 
int n, m, q;
 
struct V2D {
    ll x, y;
    V2D() : x(0), y(0) {}
    V2D(ll _x, ll _y) : x(_x), y(_y) {}
 
    inline double acos() const {
        return atan2(y, x);
    }
 
    inline ll len2() const {
        return x*x + y*y;
    }
 
    inline ld len() const {
        return sqrt(len2());
    }
 
    inline V2D operator *(const ll q) const {
        return V2D(x*q, y*q);
    }
 
    inline ll operator ^(const V2D q) const {
        return x*q.y - y*q.x;
    }
 
    inline ll operator *(const V2D q) const {
        return x*q.x + y*q.y;
    }
 
    inline V2D operator +(const V2D q)const {
        return V2D(x + q.x, y + q.y);
    }
 
    inline V2D operator -(const V2D q)const {
        return V2D(x - q.x, y - q.y);
    }
 
    inline V2D operator +=(const V2D q) {
        x += q.x, y += q.y;
        return *this;
    }
 
    inline V2D operator -=(const V2D q) {
        x -= q.x, y -= q.y;
        return *this;
    }
 
    inline void read() {
        io.rn(x), io.rn(y);
    }
};
 
const int N = 1e4 + 10;
const int M = N * 3;
const int Q = 12 + 3;
 
V2D Enemies[N];
 
struct Wall {
    V2D a, b;
} Walls[N];
 
bool ap[N];
 
V2D Base;
V2D Lv;
 
struct Node {
    V2D point;
    int type;
    double angle;
} ns[M];
 
inline ld dis(const Wall& p) {
    V2D L = p.a - p.b;
    swap(L.x, L.y);
    L.y = -L.y;
    return abs(p.a*L) * Lv.len() / abs(L*Lv);
    //return abs(p.a*L) / abs(L*Lv) * Lv.len();
    //ld v = abs(p.a*L) / L.len();
    //ld v2 = abs(L*Lv) / Lv.len() * v / L.len();
    //printf("%.4Lf: %.4Lf!\n", v, v2);
    //return v * v / v2;
}
 
class WallComp
{
public:
    inline bool operator()(const int& left, const int& right) const
    {
        double dx = dis(Walls[left]);
        double dy = dis(Walls[right]);
        return dx < dy;
    }
};
 
set<int, WallComp> s;
 
inline bool equal(double x, double y) {
    return fabs(x - y) < eps;
}
 
inline bool cmp(const Node &x, const Node &y) {
    return equal(x.angle, y.angle) ? x.type > y.type : x.angle < y.angle;
}
 
int ct = 0;
 
inline Node& AddNode(V2D v, int t) {
    Node &p = ns[ct++];
    p.point = v;
    p.angle = v.acos();
    p.type = t;
    return p;
}
 
int main() {
    int T = 0;
    while (io.rn(n) && io.rn(m) && io.rn(q)) {
        printf("Case #%d:\n", ++T);
        for (int i = 1; i <= n; ++i) Enemies[i].read();
        for (int i = 1; i <= m; ++i)
            Walls[i].a.read(), Walls[i].b.read();
 
        queue<int> ready_to;
        while (q--) {
            s.clear();
            memset(ap, 0, sizeof(ap));
            Base.read();
            ct = 0;
 
            for (int i = 1; i <= n; ++i)
                Enemies[i] -= Base;
            for (int i = 1; i <= m; ++i)
                Walls[i].a -= Base, Walls[i].b -= Base;
 
            for (int i = 1; i <= n; ++i) {
                AddNode(Enemies[i], 0);
            }
            Lv = V2D(-1, 0);
            ll dx = -1e9;
            for (int i = 1; i <= m; ++i) {
                AddNode(Walls[i].a, i);
                AddNode(Walls[i].b, i);
                V2D a = Walls[i].a;
                V2D b = Walls[i].b;
                if (min(a.y, b.y) >= 0)continue;
                if (max(a.y, b.y) < 0)continue;
                if (max(a.y, b.y) == 0) {
                    if (a.y == 0 && a.x < 0) {
                        s.insert(i);
                        ap[i] = true;
                        continue;
                    }
                    if (b.y == 0 && b.x < 0) {
                        s.insert(i);
                        ap[i] = true;
                        continue;
                    }
                    continue;
                }
                double dx = 1.0 * (abs(a.y)*b.x + abs(b.y)*a.x) / (abs(a.y) + abs(b.y));
                if (dx < 0) {
                    s.insert(i); ap[i] = true;
                }
            }
            sort(ns, ns + ct, cmp);
 
            int cur = 0, ans = 0;
            while (cur < ct) {
                Lv = ns[cur].point;
                double now = ns[cur].angle;
                ld dx = 1e9;
                bool flag = false;
                while (cur < ct) {
                    if (fabs(ns[cur].angle - now) > eps)break;
                    if (ns[cur].type == 0) {
                        if (!flag) {
                            flag = true;
                            if (s.size() > 0) dx = min(dx, dis(Walls[*s.begin()]));
                        }
                        ld d = ns[cur].point.len();
                        if (d < dx)++ans;
                        ++cur;
                        continue;
                    }
                    int t = ns[cur].type;
                    if (cur + 1 < ct && fabs(ns[cur + 1].angle - now) < eps && ns[cur + 1].type == t) {
                        dx = min(dx, min(ns[cur].point.len(), ns[cur + 1].point.len()));
                        cur += 2;
                        continue;
                    }
                    bool &x = ap[t];
                    if (x) {
                        ready_to.push(t);
                    }
                    else {
                        s.insert(t);
                    }
                    x ^= 1;
                    ++cur;
                }
                while (ready_to.size() > 0) {
                    s.erase(ready_to.front());
                    ready_to.pop();
                }
            }
            io.oln(ans);
 
            for (int i = 1; i <= n; ++i)
                Enemies[i] += Base;
            for (int i = 1; i <= m; ++i)
                Walls[i].a += Base, Walls[i].b += Base;
        }
    }
    return 0;
}