BZOJ2732[HNOI2012]射箭

题目大意

给出N条垂直于x轴的线段,求最大的K,使得存在一条经过原点,开口向下的抛物线穿过前K条线段(经过端点也算穿过),保证N条线段不重叠,且都在第一象限。

输入输出

第一行为一个整数N;

接下来N行每行3个整数x,y1,y2,描述一条线段。

数据范围

N≤100000,0<x≤1e9,0<y1<y2≤1e9。

解析

设抛物线方程为ax2+bx,则y1≤ax2+bx≤y2;

可以把每条线段看成两个关于a,b的不等式,由于是一次的,可以用半平面交验证答案。于是二分K,验证是否可行。

几个细节:

1)半平面在向量哪边要想清楚;

2)由于经过端点也算穿过,所以半平面交的边上也是可行的,极端情况所有直线交于一点,不知道有没有这种数据;

3)抛物线开口向下,对称轴在第一象限,增加2个向量限制a<0,b>0;

4)为了方便判断半平面交是否为空,可以增加2个“边框”向量,但是这两个向量的起止点坐标要足够大(反正我开1e12WA了);

5)开long double;

6)全部排序后根据id加入半平面交O(nlogn)比每次二分都排一次序O(nlog2n)优秀(废话)。

代码

        一直T竟然是因为求交点的方法不够优秀,代码过于丑陋必须加读入优化才能过qwq。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <iomanip>
  5 #include <cmath>
  6 #include <algorithm>
  7 
  8 typedef long long LL;
  9 typedef long double LD;
 10 const LD INF = 1e15;
 11 struct Point {
 12 	LD x, y;
 13 	Point(LD _x = 0, LD _y = 0):x(_x), y(_y) {};
 14 };
 15 struct Vector {
 16 	Point st, ed;
 17 	int id;
 18 	LD arg;
 19 	Vector() { memset(this, 0, sizeof(Vector)); }
 20 	Vector(Point _st, Point _ed):st(_st), ed(_ed), id(0) {};
 21 	bool operator <(const Vector &) const;
 22 	friend LD cross(const Vector &, const Vector &);
 23 	friend Point intersection(const Vector &, const Vector&);
 24 } line[200010];
 25 int N;
 26 
 27 bool judge(int);
 28 bool check(const Vector &, const Vector &, const Vector &);
 29 inline char gc();
 30 inline int read();
 31 
 32 int main() {
 33 #ifndef ONLINE_JUDGE
 34 	freopen("2732.in", "r", stdin);
 35 	freopen("2732.out", "w", stdout);
 36 #endif
 37 	N = read();
 38 	line[0] = Vector(Point(0, -INF), Point(0, INF));
 39 	line[1] = Vector(Point(-INF, 0), Point(INF, 0));
 40 	for (int i = 1; i <= N; i++) {
 41 		LD x = read(), y1 = read(), y2 = read();
 42 		line[i << 1] = Vector(Point(-1, y1 / x + x), Point(1, y1 / x - x));
 43 		line[i << 1 | 1] = Vector(Point(1, y2 / x - x), Point(-1, y2 / x + x));
 44 		line[i << 1].id = line[i << 1 | 1].id = i;
 45 	}
 46 	int l = 1, r = N;
 47 	N = (N << 1 | 1);
 48 	line[++N] = Vector(Point(-INF, INF), Point(-INF, -INF));
 49 	line[++N] = Vector(Point(INF, INF), Point(-INF, INF));
 50 	for (int i = 0; i <= N; i++)
 51 		line[i].arg = atan2(line[i].ed.y - line[i].st.y, line[i].ed.x - line[i].st.x);
 52 	std::sort(line, line + N + 1);
 53 	while (l < r) {
 54 		int mid = (l + r + 1) >> 1;
 55 		if (judge(mid)) l = mid;
 56 		else r = mid - 1;
 57 	}
 58 	printf("%d\n", l);
 59 
 60 	return 0;
 61 }
 62 bool Vector::operator <(const Vector &v) const {
 63 	if (arg != v.arg) return arg < v.arg;
 64 	else return cross(*this, Vector(st, v.st)) <= 0;
 65 }
 66 LD cross(const Vector &a, const Vector &b) {
 67 	return (a.ed.x - a.st.x) * (b.ed.y - b.st.y) - (a.ed.y - a.st.y) * (b.ed.x - b.st.x);
 68 }
 69 Point intersection(const Vector &a, const Vector &b) {
 70 	LD s1 = cross(Vector(a.st, b.ed), a);
 71 	LD s2 = cross(a, Vector(a.st, b.st));
 72 	LD t = s2 / (s1 + s2);
 73 	return Point(b.st.x + t * (b.ed.x - b.st.x), b.st.y + t * (b.ed.y - b.st.y));
 74 }
 75 bool check(const Vector &a, const Vector &b, const Vector &c) {
 76 	Point p = intersection(a, b);
 77 	return cross(Vector(c.st, p), c) > 0;
 78 }
 79 bool judge(int lim) {
 80 	static Vector ls[200010], res[200010];
 81 	int tot = 0, head = 0, tail = 0;
 82 	for (int i = 0; i <= N; i++)
 83 		if (line[i].id <= lim) ls[tot++] = line[i];
 84 	for (int i = 0; i < tot; i++) {
 85 		if (i && ls[i].arg == ls[i - 1].arg) continue;
 86 		while (tail - head > 1 && check(res[tail - 2], res[tail - 1], ls[i])) tail--;
 87 		while (tail - head > 1 && check(res[head], res[head + 1], ls[i])) head++;
 88 		res[tail++] = ls[i];
 89 	}
 90 	while (tail - head > 2 && check(res[tail - 2], res[tail - 1], res[head])) tail--;
 91 	while (tail - head > 2 && check(res[head], res[head + 1], res[tail - 1])) head++;
 92 	return tail - head > 2;
 93 }
 94 inline char gc() {
 95 	static char buf[1000000], *p1, *p2;
 96 	if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
 97 	return p1 == p2 ? EOF : *p2++;
 98 }
 99 inline int read() {
100 	int res = 0, op = 1;
101 	char ch = gc();
102 	while (ch != '-' && (ch < '0' || ch > '9')) ch = gc();
103 	if (ch == '-') op = 1, ch = gc();
104 	while (ch >= '0' && ch <= '9')
105 		res = (res << 1) + (res << 3) + ch - '0', ch = gc();
106 	return res * op;
107 }
posted @ 2019-01-14 18:37  Rhein_E  阅读(179)  评论(0编辑  收藏  举报