[AT2149] [ARC063 F] Snuke's Coloring 2

19 篇文章 0 订阅
2 篇文章 0 订阅
洛谷传送门
Atcoder传送门

题目描述

在二维笛卡尔平面上, 有一个左下角为 ( 0 , 0 ) (0,0) (0,0), 右上角为 ( W , H ) (W,H) (W,H), 边平行于 x 、 y x、y xy轴, 初始为白色的矩形, 其中有 N N N个节点。

对于每个节点 ( x i , y i ) ​ (x_i,y_i)​ (xi,yi), 你需要作出一个选择:

  • x ≤ x i ​ x\le x_i​ xxi部分的平面涂黑。
  • x ≥ x i x\ge x_i xxi部分的平面涂黑。
  • y ≤ y i ​ y\le y_i​ yyi部分的平面涂黑。
  • y ≥ y i y\ge y_i yyi部分的平面涂黑。

最后你想要矩形内白色部分的周长最大, 求这个周长。

输入输出格式

输入格式

第一行三个正整数 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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值