BZOJ 1822: [JSOI2010]Frozen Nova 冷冻波

二分时间转化为判定性问题
考虑网络流
\(S\) 向第 \(i\) 个巫妖连一条容量为 \(\dfrac{mid}{time_i}+1\) 的边
\(j\) 个精灵向 \(T\) 连一条容量为 \(1\) 的边
预处理出每个巫妖能否攻击每个精灵
通过判断圆和线段是否有交点即可
判断方法为圆心找到离线段的最近距离和半径比较

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pli pair<ll, int>
#define SZ(x) ((int)(x).size())
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) / 2)
#define lowbit(i) ((i) & (-i))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=((b)-1);i>=(a);i--)
#define Edg int ccnt=1,head[N],to[E],ne[E];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[E],ne[E],c[E];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 1000000007,INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
template<class T>T gcd(T a, T b) { while (b) { a %= b; std::swap(a, b); } return a; }
template<class T>bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<class T>bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }

const db eps = 1e-9;
inline int sign(db k) { return k < -eps ? -1 : k > eps; }
inline int cmp(db k1, db k2) { return sign(k1 - k2); }
struct P {
  db x, y;
  P() {}
  P(db x, db y): x(x), y(y) {}
  P operator + (const P &p) const { return {x + p.x, y + p.y}; }
  P operator - (const P &p) const { return {x - p.x, y - p.y}; }
  P operator * (db k) const { return {x * k, y * k}; }
  P operator / (db k) const { return {x / k, y / k}; }
  bool operator < (const P &p) const {
    int c = cmp(x, p.x);
    return c ? c == -1 : cmp(y, p.y) == -1;
  }
  bool operator == (const P &p) const {
    return !cmp(x, p.x) && !cmp(y, p.y);
  }
  db distTo(const P &p) const { return (*this - p).abs(); }
  db alpha() { return atan2(y, x); }
  void read() { scanf("%lf%lf", &x, &y); }
  void print() { printf("%.10f %.10f\n", x, y); }
  db abs() { return sqrt(abs2()); }
  db abs2() { return x * x + y * y; }
  P rot(const db &k) { return P(x * cos(k) - y * sin(k), x * sin(k) + y * cos(k)); }
  P rot90() { return P(-y, x); }
  P unit() { return *this / abs(); }
  P normal() { return rot90() / abs(); }
  int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
  P getdel() {if (sign(x) == -1 || (sign(x) == 0 && sign(y) == -1)) return (*this) * (-1); else return (*this);}
  db dot(const P &p) { return x * p.x + y * p.y; }
  db det(const P &p) { return x * p.y - y * p.x; }
};

// 点在线段上判定
bool isMiddle(db a, db m, db b) {
  return sign(a - m) == 0 || sign(b - m) == 0 || (a < m != b < m);
}
bool isMiddle(const P &a, const P &m, const P &b) {
  return isMiddle(a.x, m.x, b.x) && isMiddle(a.y, m.y, b.y);
}
// 投影
P proj(const P &p1, const P &p2, const P &q) {
  P dir = p2 - p1;
  return p1 + dir * (dir.dot(q - p1) / dir.abs2());
}
// 最近点
db nearest(const P &p1, const P &p2, const P &q) {
  P h = proj(p1, p2, q);
  if (isMiddle(p1, h, p2)) return q.distTo(h);
  return std::min(p1.distTo(q), p2.distTo(q));
}

struct Circle {
	P o; db r;
	void read() { o.read(); scanf("%lf", &r); }
	bool cut(const P &p1, const P &p2) {
		return cmp(r, nearest(p1, p2, o)) >= 0;
	}
};

const int N = 444;
P a[N], b[N];
Circle cir[N];
int n, m, k;
int maxdis[N], tim[N], mp[N][N];
bool vis[N];

namespace Dinic {
	int head[N], cnt = 1, iter[N], level[N];
	struct E {
		int v, ne, f;
	} e[N * N + 2];
	inline void add(int u, int v, int f) {
		e[++cnt].v = v; e[cnt].ne = head[u]; e[cnt].f = f; head[u] = cnt;
		std::swap(u, v);
		e[++cnt].v = v; e[cnt].ne = head[u]; e[cnt].f = 0; head[u] = cnt;
	}
	bool bfs(int s, int t) {
		for (int i = 0; i <= t; i++) level[i] = -1, iter[i] = head[i];
		std::queue<int> que;
		que.push(s);
		level[s] = 0;
		while (!que.empty()) {
			int u = que.front(); que.pop();
			for (int i = head[u]; i; i = e[i].ne) {
				int v = e[i].v, f = e[i].f;
				if (level[v] < 0 && f) {
					level[v] = level[u] + 1;
					que.push(v);
				}
			}
		}
		return level[t] != -1;
	}
	int dfs(int u, int t, int f) {
		if (u == t || !f) return f;
		int flow = 0;
		for (int i = iter[u]; i; i = e[i].ne) {
			iter[u] = i;
			int v = e[i].v;
			if (level[v] == level[u] + 1 && e[i].f) {
				int w = dfs(v, t, std::min(f, e[i].f));
				if (!w) continue;
				e[i].f -= w, e[i ^ 1].f += w;
				flow += w, f -= w;
				if (f <= 0) break;
			}
		}
		return flow;
	}
	int Maxflow(int s, int t) {
		int ans = 0;
		while (bfs(s, t)) ans += dfs(s, t, INF);
		return ans;
	}
	bool check(int cur) {
		int s = 0, t = n + m + 1;
		rep (i, 0, t + 1) head[i] = 0;
		cnt = 1;
		rep (i, 1, n + 1) 
			add(s, i, cur / tim[i] + 1);
		rep (i, 1, n + 1) 
			rep (j, 1, m + 1) {
				if (mp[i][j]) add(i, n + j, 1);
			}
		rep (i, 1, m + 1) add(n + i, t, 1);
		return Maxflow(s, t) == m;
	}
}

int main() {
#ifdef LOCAL
	freopen("ans.out", "w", stdout);
#endif
	int r = 0;
	scanf("%d%d%d", &n, &m, &k);
	rep (i, 1, n + 1) a[i].read(), scanf("%d%d", maxdis + i, tim + i), chkmax(r, tim[i]);
	rep (i, 1, m + 1) b[i].read();
	rep (i, 1, k + 1) cir[i].read();
	rep (i, 1, n + 1) {
		rep (j, 1, m + 1) {
			if (cmp(a[i].distTo(b[j]), maxdis[i]) > 0) continue;
			int flag = 1;
			rep (z, 1, k + 1) {
				if (cir[z].cut(a[i], b[j])) {
					flag = 0;
					break;
				}
			}
			if (flag) mp[i][j] = 1, vis[j] = 1;
		}
	}
	rep (i, 1, m + 1) if (!vis[i]) { puts("-1"); return 0; }
	int l = 0, ans = 0; r *= m;
	while (l <= r) {
		if (Dinic::check(mid)) ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	printf("%d\n", ans);
#ifdef LOCAL
	printf("%.10f\n", (db)clock() / CLOCKS_PER_SEC);
#endif
	return 0;
}
posted @ 2020-03-11 12:19  Mrzdtz220  阅读(95)  评论(0编辑  收藏  举报