BZOJ 2146 Construct

Construct

【问题描述】

随着改革开放的深入推进…… 小T家要拆迁了…… 当对未来生活充满美好憧憬的小T看到拆迁协议书的时候,小T从一位大好的社会主义青年变成了绝望的钉子户。 由于小T的家位于市中心,拆迁工作又难以进行,有关部门决定先把小T家用围栏围起来,以免影响市容。考虑到要建设资源节约型社会,他们希望所用的围栏长度越短越好,由于市中心寸土寸金,在围栏长度最短的情况下,围出的多边形面积越小越好。 为了简化问题,我们约定,小T的家是一个多边形,并且每条边与坐标轴平行,围栏构成的也是多边形,每条边与坐标轴平行。

【输入格式】

在第一行列出整数n——多边形的顶点的数量。在以下n行中的每一行都有两个整数——沿逆时针方向走过这个多边形顺次所经过的顶点的坐标。边界的任意三个连续顶点不在一条直线上。多边形的边界不含自交和自切。

【输出格式】

输出两行,第一行为围栏最短的长度,第二行为长度最短的前提下,最小的面积。

【样例输入】

8
0 0
9 0
9 9
6 9
6 3
3 3
3 6
0 6

【样例输出】

36
63

【数据范围】

对于100%的数据4≤n≤100000,坐标的绝对值不超过109 。


题解:

题意就是求直的凸包

那么我们把这个凸包分成左上、左下、右上、右下

把点按横坐标排下序

每一部分的纵坐标单调递增或者单调递减

用单调栈维护就好了

  1 #include<cmath>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<algorithm>
  7 using namespace std;
  8 typedef long long lar;
  9 const int maxn = 2e5 + 233;
 10 const lar inf = 2e9;
 11 int n;
 12 int top;
 13 int num;
 14 lar ans;
 15 struct point
 16 {
 17     lar x, y;
 18     inline void print()
 19     {
 20         printf("%lld %lld\n", x, y);
 21     }
 22     friend inline lar operator * (point a, point b)
 23     {
 24         return a.x * b.y - a.y * b.x;
 25     }
 26 };
 27 point mi, ma;
 28 point p[maxn];
 29 point s[maxn];
 30 inline bool hor(point a, point b)
 31 {
 32     return (a.x != b.x) ? a.x < b.x : a.y < b.y;
 33 }
 34 inline void Scan(int &x)
 35 {
 36     char c;
 37     bool o = false;
 38     while(!isdigit(c = getchar())) o = (c != '-') ? o : true;
 39     x = c - '0';
 40     while(isdigit(c = getchar())) x = x * 10 + c - '0';
 41     if(o) x = -x;
 42 }
 43 inline void Max(point &a, point b)
 44 {
 45     a.x = max(a.x, b.x);
 46     a.y = max(a.y, b.y);
 47 }
 48 inline void Min(point &a, point b)
 49 {
 50     a.x = min(a.x, b.x);
 51     a.y = min
 52     (a.y, b.y);
 53 }
 54 int main()
 55 {
 56     Scan(n);
 57     int x, y;
 58     for(int i = 1; i <= n; ++i)
 59     {
 60         Scan(x), Scan(y);
 61         p[i] = (point) {x, y};
 62     }
 63     sort(p + 1, p + 1 + n, hor);
 64     int up, be;
 65     point mi, ma;
 66     mi.x = mi.y = inf;
 67     ma.x = ma.y = -inf;
 68     for(int i = 1; i <= n; ++i)
 69     {
 70         Max(ma, p[i]);
 71         Min(mi, p[i]);
 72     }
 73     int now = 1;
 74     while(now <= n)
 75     {
 76         if(!top || p[now].y >= s[top].y) s[++top] = p[now];
 77         if(p[now++].y == ma.y) break;
 78     }
 79     while(now <= n)
 80     {
 81         while(p[now].y > s[top].y) --top;
 82         s[++top] = p[now++];
 83     }
 84     for(int i = 1; i < top; ++i) ans += min(s[i + 1].y, s[i].y) * (s[i + 1].x - s[i].x);
 85     top = 0;
 86     now = 1;
 87     while(now <= n)
 88     {
 89         if(!top || p[now].y <= s[top].y) s[++top] = p[now];
 90         if(p[now++].y == mi.y) break;
 91     }
 92     while(now <= n)
 93     {
 94         while(p[now].y < s[top].y) --top;
 95         s[++top] = p[now++];
 96     }
 97     for(int i = 1; i < top; ++i) ans -= max(s[i + 1].y, s[i].y) * (s[i + 1].x - s[i].x);
 98     lar one = (ma.x + ma.y - mi.x - mi.y) << 1;
 99     printf("%lld\n%lld", one, ans);
100 }

转载于:https://www.cnblogs.com/lytccc/p/6899465.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值