codeforces 70D Professor's task(动态二维凸包)

本文介绍了一个用于动态凸包问题的高效算法,包括增量法求解过程及代码实现细节。通过实例演示了如何处理添加点和判断点是否在凸包内的操作,特别强调了代码的优化及复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://codeforces.com/contest/70/problem/D

Once a walrus professor Plato asked his programming students to perform the following practical task.

The students had to implement such a data structure that would support a convex hull on some set of points S. The input to the program had q queries of two types:

1. Add a point with coordinates (x, y) into the set S. Note that in this case the convex hull of S could have changed, and could have remained the same.

2. Say whether a point with coordinates (x, y) belongs to an area limited by the convex hull, including the border.

All the students coped with the task. What about you?

Input

The first line contains an integer q (4 ≤ q ≤ 105).

Then follow q lines in the following way: "t x y", where t is the query type (1 or 2), and (x, y) are the coordinates of the point ( - 106 ≤ x, y ≤ 106, x and y are integers).

There is at least one query of type 2.

It is guaranteed that the three queries of the first type follow first and the points given in the queries form a non-degenerative triangle. Also all the points added in S are distinct.

Output

For each query of the second type print one string containing "YES", if the point lies inside the convex hull or on its border. Otherwise, print "NO".

 

题目大意:q个操作。操作1:往点集中添加一个点。操作2:给一个点,问这个点是否在点集所构成的凸包内部(包括边缘)。

思路:增量法求动态凸包。可以看:http://blog.youkuaiyun.com/crazy_ac/article/details/8499443

PS:原来map的迭代器是首尾相连的……

 

代码(156MS):

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <map>
 6 using namespace std;
 7 typedef long long LL;
 8 typedef map<int, int> MPII;
 9 
10 struct Point {
11     int x, y;
12     Point() {}
13     Point(int x, int y): x(x), y(y) {}
14     Point(MPII::iterator it): x(it->first), y(it->second) {}
15     Point operator - (const Point &rhs) const {
16         return Point(x - rhs.x, y - rhs.y);
17     }
18 };
19 
20 LL cross(const Point &a, const Point &b) {
21     return (LL)a.x * b.y - (LL)a.y * b.x;
22 }
23 
24 LL cross(const Point &o, const Point &a, const Point &b) {
25     return cross(a - o, b - o);
26 }
27 
28 bool below(MPII &mp, Point p) {
29     if(mp.empty()) return false;
30     if(p.x < mp.begin()->first || mp.rbegin()->first < p.x) return false;
31     MPII::iterator a = mp.lower_bound(p.x), b = a--;
32     if(b->first == p.x) return b->second >= p.y;
33     return cross(a, b, p) <= 0;
34 }
35 
36 void insert(MPII &mp, Point p) {
37     if(below(mp, p)) return ;
38     MPII::iterator a, b, it;
39     mp[p.x] = p.y;
40     it = mp.lower_bound(p.x);
41 
42     b = it; ++b;
43     if(b != mp.end()) {
44         a = b++;
45         while(b != mp.end() && cross(p, a, b) >= 0)
46             mp.erase(a), a = b++;
47     }
48 
49     a = it; --a;
50     if(it != mp.begin() && a != mp.begin()) {
51         b = a--;
52         while(b != mp.begin() && cross(p, b, a) <= 0)
53             mp.erase(b), b = a--;
54     }
55 }
56 
57 MPII up, down;
58 int q, op, x, y;
59 
60 int main() {
61     scanf("%d", &q);
62     while(q--) {
63         scanf("%d%d%d", &op, &x, &y);
64         if(op == 1) {
65             insert(up, Point(x, y));
66             insert(down, Point(x, -y));
67         } else {
68             puts((below(up, Point(x, y)) && below(down, Point(x, -y))) ? "YES" : "NO");
69         }
70     }
71 }
View Code

 

转载于:https://www.cnblogs.com/oyking/p/3910539.html

### Codeforces二维前缀和的应用 在解决涉及矩阵区域查询的问题时,二维前缀和是一种非常有效的工具。通过预先计算部分和,可以在常数时间内快速获取任意子矩形内的元素总和。 #### 什么是二维前缀和? 对于一个大小为 \( m \times n \) 的矩阵 `A`,定义其对应的前缀和矩阵 `sum` 如下: \[ sum[i][j] = A[0...i-1][0...j-1] \] 即 `sum[i][j]` 表示从原点 `(0, 0)` 到位置 `(i-1, j-1)` 所构成的矩形区域内所有元素之和[^2]。 为了方便处理边界情况,通常会将索引偏移一位,在实际编程中使用 `sum[i+1][j+1]` 来表示上述范围内的累加值。 #### 计算方法 构建前缀和的过程可以通过双重循环完成,时间复杂度为 O(mn),其中 m 和 n 分别代表矩阵的高度和宽度。核心代码如下所示: ```cpp for(int i = 1; i <= h; ++i){ for(int j = 1; j <= w; ++j){ // 当前格子加上左边、上面以及左上的三个方向已经累积的结果 sum[i][j] = A[i-1][j-1] + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1]; } } ``` 这里需要注意减去重复计算的部分 `- sum[i-1][j-1]`,因为这部分被前面两次相加操作多算了。 #### 查询指定矩形区域的和 假设要查询以坐标 `(x1,y1)` 作为左上角顶点,`(x2,y2)` 作为右下角顶点所围成的小矩形内部数值总和,则可以按照下面的方式进行计算: \[ query(x_1, y_1, x_2, y_2)=sum[x_2][y_2]-sum[x_1-1][y_2]-sum[x_2][y_1-1]+sum[x_1-1][y_1-1]\] 这同样遵循了容斥原理来排除重叠部分的影响。 #### 实际应用案例 考虑这样一个题目:“在一个整数矩阵中找到满足特定条件的最大/最小面积”。这类问题往往需要频繁地对不同尺寸的子矩形做求和运算,而借助于预处理好的前缀和表就可以大大简化这些操作并提高效率。 例如,在某些情况下可能还需要结合其他数据结构如线段树或者二分查找来进行更复杂的优化;而在另一些场景里则可以直接利用简单的四边形不等式性质加速搜索过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值