多校第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;
}