1. 程式人生 > >【LOJ2329】「清華集訓 2017」我的生命已如風中殘燭

【LOJ2329】「清華集訓 2017」我的生命已如風中殘燭

【題目連結】

【思路要點】

  • 一個直觀的思路是模擬該過程,當路上遇到環的時候通過類似取模的手段加速。
  • 注意到每繞一個環 L L 的長度至少減半,因此繞環的個數不會超過 O
    ( L o g L ) O(LogL)
    。並且一個點如果在某一時刻不能夠到,那麼這個點就不會再被夠到,所以找到一個環至多需要遍歷 O
    ( N ) O(N)
    個點,因此如果我們預處理每個點作為原點時極角排序的結果,這個做法單組資料的時間複雜度為 O (
    N 2 L o g N + M N 2 L o g L ) O(N^2LogN+MN^2LogL)
    ,可以用 S T ST 表優化至 O ( N 2 L o g N + M N L o g N L o g L ) O(N^2LogN+MNLogNLogL) ,應該已經能夠通過本題。
  • 進一步考慮,每一個環都是一個凸包,假設當前點為 B B ,其在凸包上的前驅為 A A ,我們直接暴力找 B B 的後繼 C C 會掃描射線 A B AB 和射線 B C BC 的夾角內的所有點,而每個點至多屬於 O ( 1 ) O(1) 個這樣的區域,因此暴力找到一個環的時間複雜度就是 O ( N ) O(N) 。這個做法單組資料的時間複雜度為 O ( N 2 L o g N + M N L o g L ) O(N^2LogN+MNLogL)
  • 時間複雜度 O ( T ( N 2 L o g N + M N L o g L ) ) O(T*(N^2LogN+MNLogL))

【程式碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e3 + 5;
const double pi = acos(-1);
const double eps = 1e-8;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct point {int x, y; };
point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; }
point operator * (point a, int b) {return (point) {a.x * b, a.y * b}; }
ll operator * (point a, point b) {return 1ll * a.x * b.y - 1ll * a.y * b.x; }
double dist(point a) {return sqrt(1ll * a.x * a.x + 1ll * a.y * a.y); }
double PolarAngle(point a) {return atan2(a.y, a.x); }
struct info {int pos; double dist, alpha; };
bool cmp(info a, info b) {
	if (fabs(a.alpha - b.alpha) <= eps) return a.dist < b.dist;
	else return a.alpha < b.alpha;
}
int n, m, home[MAXN][MAXN];
point s, t; double l;
info a[MAXN][MAXN];
point p[MAXN];
int work(int pos, int from, double len) {
	if (from == n + 1) {
		double tmp = PolarAngle(p[pos] - s) + 4 * pi;
		for (int i = 1; i <= 3 * n - 3; i++)
			if (a[pos][i].alpha < tmp - eps && a[pos][i].dist < len) return 1 + work(a[pos][i].pos, pos, len - a[pos][i].dist);
		return 0;
	} else {
		int ans = 0, tot = 0;
		static int path[MAXN], vis[MAXN];
		memset(vis, 0, sizeof(vis));
		path[++tot] = pos;
		while (vis[pos] == 0) {
			vis[pos] = tot;
			int nxt = 0;
			for (int i = home[pos][from]; i <= 3 * n - 3; i++)
				if (a[pos][i].dist < len) {
					ans++;
					nxt = a[pos][i].pos;
					len -= a[pos][i].dist;
					break;
				}
			if (nxt == 0) return ans;
			else {
				from = pos;
				pos = nxt;
			}
			path[++tot] = pos;
		}
		int start = vis[pos];
		for (int i = start; i < tot; i++) {
			int nxt = 0;
			for (int i = home[pos][from]; i <= 3 * n - 3; i++)
				if (a[pos][i].dist < len) {
					ans++;
					nxt = a[pos][i].pos;
					len -= a[pos][i].dist;
					break;
				}
			if (nxt == 0) return ans;
			else {
				from = pos;
				pos = nxt;
				if (pos != path[i + 1]) return ans + work(pos, from, len);
			}
		}
		double c = 0;
		for (int i = start; i < tot; i++)
			c += dist(p[path[i]] - p[path[i + 1]]);
		int q = len / c;
		len -= q * c, ans += (tot - vis[pos]) * q;
		return ans + work(path[tot], path[tot - 1], len);
	}
}
int main() {
	int T; read(T);
	while (T--) {
		read(n), read(m);
		for (int i = 1; i <= n; i++)
			read(p[i].x), read(p[i].y);
		for (int i = 1; i <= n; i++) {
			int tot = 0;
			for (int j = 1; j <= n; j++)
				if (i != j) a[i][++tot] = (info) {j, dist(p[i] - p[j]), PolarAngle(p[j] - p[i])};
			sort(a[i] + 1, a[i] + tot + 1, cmp);
			for (int j = 1; j <= tot; j++) {
				a[i][j + tot] = a[i][j];
				a[i][j + tot].alpha += 2 * pi;
				a[i][j + tot * 2] = a[i][j];
				a[i][j + tot * 2].alpha += 4 * pi;
			}
			reverse(a[i] + 1, a[i] + tot * 3 + 1);
			int pos = 1;
			for (int j = 1; j <= tot; j++) {
				while (a[i][j].alpha - a[i][pos].alpha <= pi - eps) pos++;
				home[i][a[i][j].pos] = pos;
			}
		}
		for (int i = 1; i <= m; i++) {
			read(s.x), read(s.y);
			read(t.x), read(t.y);
			read(l); int tot = 0;
			static info tmp[MAXN];
			tmp[++tot] = (info) {n + 1, l, PolarAngle(t - s)};
			for (int j = 1; j <= n; j++)
				tmp[++tot] = (info) {j, dist(p[j] - s), PolarAngle(p[j] - s)};
			sort(tmp + 1, tmp + tot + 1, cmp);
			for (int j = 1; j <= tot; j++)