BZOJ2146 Construct

题目大意

给出一个多边形A(保证边平行于坐标轴),要用另一个多边形B(边也必须平行于坐标轴)把A围起来,求:

1)B的最小周长;

2)B在满足1)的前提下的最小面积。

输入输出

输入A的边数N,和N个顶点的坐标(均为整数)。

输出1)和2)的答案,各占一行。

数据范围

4≤N≤100000,坐标的绝对值≤1e9

解析

1)对于第一问,可以把B等价为一个边平行于坐标轴的矩形,于是答案显而易见的等于(max_x – min_x + max_y – min_y) * 2;(然而我最开始SB地求了个凸包……)

2)对于第二问,为了满足B的边长最小,“凹进去”的边显然不可取,由于边平行于坐标轴,我们可以把点按x排序,上下两个单调栈维护y,需要注意的是只有当出现“凹”形的时候才能pop,也就是说实际上维护的是一个“峰”(大概不叫单调栈了):

clip_image002

还有就是y相等的点不能直接pop掉。

然后从左到右一段一段地算面积加入答案即可,具体见代码。

代码

求了凸包的版本:

  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 const LL INF = 0x3f3f3f3f3f3f3f3f;
 10 struct Point {
 11     LL x, y;
 12     Point(LL _x = 0, LL _y = 0):x(_x), y(_y) {};
 13     Point operator -(const Point &) const;
 14     bool operator <(const Point &) const;
 15     friend LL cross(const Point &, const Point &);
 16 } point[100010];
 17 int N, convex[100010], tail;
 18 
 19 void calculate_convex();
 20 LL calculate_perimeter();
 21 LL calculate_area();
 22 
 23 int main() {
 24 #ifndef ONLINE_JUDGE
 25     freopen("2146.in", "r", stdin);
 26     freopen("2146.out", "w", stdout);
 27 #endif
 28     std::ios::sync_with_stdio(false);
 29     std::cin >> N;
 30     for (int i = 0; i < N; i++)
 31         std::cin >> point[i].x >> point[i].y;
 32     std::sort(point, point + N);
 33     calculate_convex();
 34     std::cout << calculate_perimeter() << std::endl << calculate_area() << std::endl;
 35 
 36     return 0;
 37 }
 38 Point Point::operator -(const Point &p) const { return Point(x - p.x, y - p.y); }
 39 bool Point::operator <(const Point &p) const { return x == p.x ? y < p.y : x < p.x; }
 40 LL cross(const Point &a, const Point &b) { return a.x * b.y - a.y * b.x; }
 41 void calculate_convex() {
 42     for (int i = 0; i < N; i++) {
 43         while (tail > 1 && cross(point[convex[tail - 1]] - point[convex[tail - 2]], point[i] - point[convex[tail - 1]]) >= 0)
 44             tail--;
 45         convex[tail++] = i;
 46     }
 47     int size_up = tail - 1;
 48     for (int i = N - 2; i >= 0; i--) {
 49         while (tail - size_up > 1 && cross(point[convex[tail - 1]] - point[convex[tail - 2]], point[i] - point[convex[tail - 1]]) >= 0)
 50             tail--;
 51         convex[tail++] = i;
 52     }
 53     tail--;
 54 }
 55 LL calculate_perimeter() {
 56     LL res = 0;
 57     for (int i = 0; i < tail; i++) {
 58         res += abs(point[convex[i]].x - point[convex[i + 1]].x);
 59         res += abs(point[convex[i]].y - point[convex[i + 1]].y);
 60     }
 61     return res;
 62 }
 63 LL calculate_area() {
 64     int stk1[100010], top1 = 0, stk2[100010], top2 = 0;
 65     LL res = 0, maxy = -INF, miny = INF;
 66     for (int i = 0; i < N; i++) {
 67         while (top1 > 0 && point[i].y > point[stk1[top1 - 1]].y && maxy > point[stk1[top1 - 1]].y)
 68             --top1;
 69         stk1[top1++] = i;
 70         maxy = std::max(maxy, point[i].y);
 71         while (top2 > 0 && point[i].y < point[stk2[top2 - 1]].y && miny < point[stk2[top2 - 1]].y)
 72             --top2;
 73         stk2[top2++] = i;
 74         miny = std::min(miny, point[i].y);
 75     }
 76     LL tmp1 = point[stk1[0]].y, tmp2 = point[stk2[0]].y;
 77     for (int i = 0, j = 0, lastx = point[0].x; i < top1;) {
 78         while (j < top2 && point[stk2[j]].x <= point[stk1[i]].x) {
 79             res += (point[stk2[j]].x - lastx) * (tmp1 - tmp2);
 80             lastx = point[stk2[j]].x;
 81             ++j;
 82             if (j < top2) tmp2 = std::max(point[stk2[j]].y, point[stk2[j - 1]].y);
 83             else tmp2 = point[stk2[j - 1]].y;
 84         }
 85         res += (point[stk1[i]].x - lastx) * (tmp1 - tmp2);
 86         lastx = point[stk1[i]].x;
 87         ++i;
 88         tmp1 = std::min(point[stk1[i]].y, point[stk1[i - 1]].y);
 89     }
 90     return res;
 91 }

正常版本:

  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 const LL INF = 0x3f3f3f3f3f3f3f3f;
 10 struct Point {
 11 	LL x, y;
 12 	Point(LL _x = 0, LL _y = 0):x(_x), y(_y) {};
 13 	bool operator <(const Point &) const;
 14 } point[100010];
 15 int N;
 16 
 17 LL calculate_perimeter();
 18 LL calculate_area();
 19 
 20 int main() {
 21 #ifndef ONLINE_JUDGE
 22 	freopen("2146.in", "r", stdin);
 23 	freopen("2146.out", "w", stdout);
 24 #endif
 25 	std::ios::sync_with_stdio(false);
 26 	std::cin >> N;
 27 	for (int i = 0; i < N; i++)
 28 		std::cin >> point[i].x >> point[i].y;
 29 	std::sort(point, point + N);
 30 	std::cout << calculate_perimeter() << std::endl << calculate_area() << std::endl;
 31 
 32 	return 0;
 33 }
 34 bool Point::operator <(const Point &p) const { return x == p.x ? y < p.y : x < p.x; }
 35 LL calculate_perimeter() {
 36 	LL maxx = -INF, minx = INF, maxy = -INF, miny = INF;
 37 	for (int i = 0; i < N; i++) {
 38 		maxx = std::max(maxx, point[i].x);
 39 		minx = std::min(minx, point[i].x);
 40 		maxy = std::max(maxy, point[i].y);
 41 		miny = std::min(miny, point[i].y);
 42 	}
 43 	return (maxx - minx + maxy - miny) << 1;
 44 }
 45 LL calculate_area() {
 46 	int stk1[100010], top1 = 0, stk2[100010], top2 = 0;
 47 	LL res = 0, maxy = -INF, miny = INF;
 48 	for (int i = 0; i < N; i++) {
 49 		while (top1 > 0 && point[i].y > point[stk1[top1 - 1]].y && maxy > point[stk1[top1 - 1]].y)
 50 			--top1;
 51 		stk1[top1++] = i;
 52 		maxy = std::max(maxy, point[i].y);
 53 		while (top2 > 0 && point[i].y < point[stk2[top2 - 1]].y && miny < point[stk2[top2 - 1]].y)
 54 			--top2;
 55 		stk2[top2++] = i;
 56 		miny = std::min(miny, point[i].y);
 57 	}
 58 	LL tmp1 = point[stk1[0]].y, tmp2 = point[stk2[0]].y;
 59 	for (int i = 0, j = 0, lastx = point[0].x; i < top1;) {
 60 		while (j < top2 && point[stk2[j]].x <= point[stk1[i]].x) {
 61 			res += (point[stk2[j]].x - lastx) * (tmp1 - tmp2);
 62 			lastx = point[stk2[j]].x;
 63 			++j;
 64 			if (j < top2) tmp2 = std::max(point[stk2[j]].y, point[stk2[j - 1]].y);
 65 			else tmp2 = point[stk2[j - 1]].y;
 66 		}
 67 		res += (point[stk1[i]].x - lastx) * (tmp1 - tmp2);
 68 		lastx = point[stk1[i]].x;
 69 		++i;
 70 		tmp1 = std::min(point[stk1[i]].y, point[stk1[i - 1]].y);
 71 	}
 72 	return res;
 73 }
posted @ 2019-01-14 10:28  Rhein_E  阅读(255)  评论(0编辑  收藏  举报