洛谷传送门
Atcoder传送门
题目描述
在二维笛卡尔平面上, 有一个左下角为 ( 0 , 0 ) (0,0) (0,0), 右上角为 ( W , H ) (W,H) (W,H), 边平行于 x 、 y x、y x、y轴, 初始为白色的矩形, 其中有 N N N个节点。
对于每个节点 ( x i , y i ) (x_i,y_i) (xi,yi), 你需要作出一个选择:
- 将 x ≤ x i x\le x_i x≤xi部分的平面涂黑。
- 将 x ≥ x i x\ge x_i x≥xi部分的平面涂黑。
- 将 y ≤ y i y\le y_i y≤yi部分的平面涂黑。
- 将 y ≥ y i y\ge y_i y≥yi部分的平面涂黑。
最后你想要矩形内白色部分的周长最大, 求这个周长。
输入输出格式
输入格式
第一行三个正整数 W , H , N W,H, N W,H,N。
以下 N N N行, 每行两个正整数 x i , y i x_i,y_i xi,yi, 保证没有两个点在同一行/一列。
输出格式
输出一个正整数, 表示最大的周长。
输入输出样例
输入样例#1:
10 10 4
1 6
4 1
6 9
9 4
输出样例#1:
32
输入样例#2:
5 4 5
0 0
1 1
2 2
4 3
5 4
输出样例#2:
12
输入样例#3:
100 100 8
19 33
8 10
52 18
94 2
81 36
88 95
67 83
20 71
输出样例#3:
270
输入样例#4:
100000000 100000000 1
3 4
输出样例#4:
399999994
解题分析
首先, 因为没有两个点在同一行或同一列, 那么答案至少为 m a x ( W , H ) + 2 max(W,H)+2 max(W,H)+2。 这意味着答案一定过 y = H 2 y=\frac{H}{2} y=2H或 x = W 2 x=\frac{W}{2} x=2W。
那么直接一个单调栈加线段树维护围的最大面积就好了…
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <climits>
#include <algorithm>
#include <vector>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 300500
#define ll long long
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int n, tup, tdown, w, h, ans;
int up[MX], down[MX];
struct Cood {int x, y;} dat[MX];
IN bool operator < (const Cood &x, const Cood &y) {return x.x < y.x;}
namespace SGT
{
#define ls (now << 1)
#define rs (now << 1 | 1)
int tag[MX << 2], mx[MX << 2];
IN void pushup(R int now) {mx[now] = max(mx[ls], mx[rs]);}
IN void pushdown(R int now)
{
if (tag[now])
{
mx[ls] += tag[now], tag[ls] += tag[now];
mx[rs] += tag[now], tag[rs] += tag[now];
tag[now] = 0;
}
}
void modify(R int now, R int lef, R int rig, R int lb, R int rb, R int val)
{
if (lef >= lb && rig <= rb) return tag[now] += val, mx[now] += val, void();
int mid = lef + rig >> 1; pushdown(now);
if (lb <= mid) modify(ls, lef, mid, lb, rb, val);
if (rb > mid) modify(rs, mid + 1, rig, lb, rb, val);
pushup(now);
}
int query(R int now, R int lef, R int rig, R int lb, R int rb)
{
if (lef >= lb && rig <= rb) return mx[now];
int mid = lef + rig >> 1, ret = -INT_MAX; pushdown(now);
if (lb <= mid) ret = query(ls, lef, mid, lb, rb);
if (rb > mid) ret = max(ret, query(rs, mid + 1, rig, lb, rb));
return ret;
}
}
void solve()
{
int mid = h >> 1;
tup = tdown = 0;
up[0] = down[0] = 1;
std::sort(dat + 2, dat + 1 + n);
SGT::modify(1, 1, n, 1, n, h << 1);
for (R int i = 2; i <= n; ++i)
{
SGT::modify(1, 1, n, 1, i - 1, (dat[i].x - dat[i - 1].x) << 1);
ans = max(ans, SGT::mx[1]);
if (dat[i].y >= mid)
{
SGT::modify(1, 1, n, up[tup], i - 1, (dat[i].y - h) << 1);
W (tup && dat[up[tup]].y >= dat[i].y)
{
SGT::modify(1, 1, n, up[tup - 1], up[tup] - 1, (dat[i].y - dat[up[tup]].y) << 1);
--tup;
}
up[++tup] = i;
}
else
{
SGT::modify(1, 1, n, down[tdown], i - 1, -(dat[i].y << 1));
W (tdown && dat[down[tdown]].y <= dat[i].y)
{
SGT::modify(1, 1, n, down[tdown - 1], down[tdown] - 1, (dat[down[tdown]].y - dat[i].y) << 1);
--tdown;
}
down[++tdown] = i;
}
}
}
int main(void)
{
in(w), in(h), in(n); ++n;
for (R int i = 2; i <= n; ++i) in(dat[i].x), in(dat[i].y);
dat[++n] = {w, h};
solve();
std::memset(SGT::tag, 0, sizeof(SGT::tag));
std::memset(SGT::mx, 0, sizeof(SGT::mx));
std::swap(w, h);
for (R int i = 2; i <= n; ++i) std::swap(dat[i].x, dat[i].y);
solve();
printf("%d", ans);
}