因为这题考虑可以观察一个性质,答案的下界为 \(2×(max(w,h)+1)\), 因为你至少可以空出一行或一列,因此这个矩形一定会经过 \(x=\frac{w}{2}\) 或 \(y=\frac{h}{2}\) . 先考虑经过 \(\frac{w}{2}\) 的情况 , 另一种情况是一样的.

先将坐标离散化.枚举矩形的上边界 \(yR\) ,对于每一个下边界 \(yL\) , 我们可以计算出矩形的最优左边界 \(xL=min\{Xi|Yi\in[yL,yR],Xi>\frac{w}{2}\}\) , 以 及 右 边 界 \(xR=max\{Xi|Yi\in[yL,yR],Xi≤\frac{w}{2}\}\) ,

此时可以找到一个周长为 \(2×(xR−xL+yR−yL)\) 的矩形.

直接做是 \(O(n^2)\) 的,但该算法可以用线段树优化,在将上边界往上移的过程中动态维护每

个位置的 xL,xR,并维护全局最小值,不难发现只需要左右各开一个单调栈,在更新单调栈

时在线段树树上进行区间加减即可. O(nlogn) .

这其实就是一个计算极大subrectangle的过程, 因为知道中间边界, 基本原理来自于暴力, 就是简单的枚举长度, 更新宽度. 其实这题也很套路, 发现这题的边界是不断移动的, 在移动的时候会产生一部分的重复信息, 所以考虑采用数据结构维护, 分析一下颓余状态, 发现可以单调栈优化.

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
int read() {
char ch = getchar();
int x = 0, flag = 1;
for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
return x * flag;
}
void write(int x) {
if (x < 0) putchar('-'), x = -x;
if (x >= 10) write(x / 10);
putchar(x % 10 + 48);
} const int Maxn = 3e5 + 9;
struct Point {
int x, y;
int operator < (const Point &a) const {
return x < a.x;
}
}s[Maxn];
int n, ans, h, w; void init() {
w = read(), h = read(); n = read();
rep (i, 1, n) s[i].x = read(), s[i].y = read();
s[++n] = (Point){0, 0};
s[++n] = (Point){w, h};
} pair<int, int> stkA[Maxn], stkB[Maxn];
int topa, topb; struct SGMTtree {
int tree[Maxn << 2], add[Maxn << 2];
#define lc(x) ((x) << 1)
#define rc(x) ((x) << 1 | 1)
#define ls rt << 1, l, mid
#define rs rt << 1 | 1, mid + 1, r void clear() {
clar(tree, 0), clar(add, 0);
}
void pushup(int rt) {
tree[rt] = max(tree[lc(rt)], tree[rc(rt)]);
}
void pushdown(int rt) {
if (add[rt]) {
add[lc(rt)] += add[rt]; add[rc(rt)] += add[rt];
tree[lc(rt)] += add[rt]; tree[rc(rt)] += add[rt];
add[rt] = 0;
}
}
void modify(int rt, int l, int r, int p, int q, int v) {
if (p <= l && r <= q) {
add[rt] += v; tree[rt] += v;
return ;
} int mid = (l + r) >> 1; pushdown(rt);
if (q <= mid) modify(ls, p, q, v);
else if (p >= mid + 1) modify(rs, p, q, v);
else modify(ls, p, q, v), modify(rs, p, q, v);
pushup(rt);
}
#undef lc
#undef rc
#undef ls
#undef rs
}st; void ZhaoQingFei() {
sort(s + 1, s + n + 1); st.clear(); topa = topb = 0;
rep (i, 1, n) {
int Nxt = i - 1;
if (s[i].y <= h / 2) {
while (topa && stkA[topa].second <= s[i].y) {
st.modify(1, 1, n, stkA[topa].first, Nxt, stkA[topa].second - s[i].y);
Nxt = stkA[topa].first - 1; --topa;
}
if (Nxt != i - 1) stkA[++topa] = make_pair(Nxt + 1, s[i].y);
} else {
while (topb && stkB[topb].second >= s[i].y) {
st.modify(1, 1, n, stkB[topb].first, Nxt, s[i].y - stkB[topb].second);
Nxt = stkB[topb].first - 1; --topb;
}
if (Nxt != i - 1) stkB[++topb] = make_pair(Nxt + 1, s[i].y);
}
stkA[++topa] = make_pair(i, 0);
stkB[++topb] = make_pair(i, h); st.modify(1, 1, n, i, i, h - s[i].x);
ans = max(ans, s[i + 1].x + st.tree[1]);
}
} void solve() {
ZhaoQingFei(); rep (i, 1, n) swap(s[i].x, s[i].y);
swap(h, w); ZhaoQingFei();
cout << ans * 2 << endl;
} int main() {
// freopen("ARC047B.in", "r", stdin);
// freopen("ARC047B.out", "w", stdout); init();
solve(); #ifdef Qrsikno
debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
return 0;
}

更新防死

[arc063]F.すぬけ君の塗り絵2的更多相关文章

  1. ARC063F すぬけ君の塗り絵 2 / Snuke's Coloring 2

    题面 一句话题面:给你一些点,求这些点之中夹的最大的矩形周长.(考虑边界) Solution 首先是一个结论,答案矩形一定经过\(x=\frac{w}{2}\)或经过\(y=\frac{h}{2}\) ...

  2. すぬけ君の塗り絵 / Snuke's Coloring AtCoder - 2068 (思维,排序,贡献)

    Problem Statement We have a grid with H rows and W columns. At first, all cells were painted white. ...

  3. 【AtCoder】ARC063

    ARC063 C - 一次元リバーシ / 1D Reversi 不同的颜色段数-1 #include <bits/stdc++.h> #define fi first #define se ...

  4. 【AtCoder】ARC061

    ARC061 C - たくさんの数式 / Many Formulas 这个其实\(10^5\)也能做.. 就是\(dp[i]\)表示到第i位的方案数,\(sum[i]\)表示延伸到第i位之前的所有方案 ...

  5. DP题组

    按照顺序来. Median Sum 大意: 给你一个集合,求其所有非空子集的权值的中位数. 某集合的权值即为其元素之和. 1 <= n <= 2000 解: 集合配对,每个集合都配对它的补 ...

  6. csp退役前的做题计划1(真)

    csp退役前的做题计划1(真) 因为我太菜了,所以在第一次月考就会退役,还是记录一下每天做了什么题目吧. 任务计划 [ ] Z算法(Z Algorithm) 9.28 [x] ARC061C たくさん ...

  7. es6 解构赋值

    ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 关于给变量赋值,传统的变量赋值是这样的: var arr = [1,2,3];//把数组的值 ...

  8. php debug二三事

    最近php相关项目遇到了一些问题,处理起来让人感觉挺有意思,寥寥记下. 1.php执行后常驻内存里,需要kill掉该进程再重启,才能让修改后的代码生效. 之前有一次组里小伙伴修改了一个长期后台进程运行 ...

  9. Unicode字符集的由来

    *:first-child { margin-top: 0 !important; } .markdown-body>*:last-child { margin-bottom: 0 !impor ...

随机推荐

  1. Fastjson 简介

    Fastjson is a Java library that can be used to convert Java Objects into their JSON representation. ...

  2. (linux)idr(integer ID management)机制

     最近研究进程间通信,遇到了idr相关的函数,为了扫清障碍,先研究了linux的idr机制. IDR(integer ID management)的要完成的任务是给要管理的对象分配一个唯一的ID,于 ...

  3. ALSA lib调用实例

    1. Display Some PCM Types and Formats 2. Opening PCM Device and Setting Parameters /* This example o ...

  4. codeforces 463A Caisa and Sugar 解题报告

    题目链接:http://codeforces.com/problemset/problem/463/A 题目意思:某个人有 s dollar的钱,有 n 种类型的糖果,第 i 种糖果的价值为 xi d ...

  5. css元素定位样式

    曾经写网页,学css整体上不难,但就是元素定位,始终一知半解,直到今天,本着实践出真知的理念,经过认真测试,总结出了如下结论. css 定位: positionstatic : 默认静止定位,元素在正 ...

  6. JQ里的this与$(this)

    网上有很多关于jQuery的this和$(this)的介绍,大多数只是理清了this和$(this)的指向,其实它是有应用场所的,不能一概而论在jQuery调用成员函数时,this就是指向dom对象. ...

  7. emacs设置tab缩进

    这两天使用Emacs自带的JavaScriptMode时,发现与其它编辑器下缩进不同,而且用emacs重新缩进对齐后,再用其它的编辑器打时缩进却乱掉了.分析应该是Tab缩进的问题,在.emacs中增加 ...

  8. [转载]Dalvik指令集

    这篇文章是转载的,为了便于查找一些指令,贴在这里. 转自:http://blog.csdn.net/canfengxiliu/article/details/20144119 ------------ ...

  9. 属性(@property)的修饰词有哪些,各自是什么作用,在哪种情况下用?

       之前面试了几家公司,都会问到这个基础的问题,以前,没有怎么注意,所以答的很混乱,所以查了查网上的资料,特意整理了一份.   常见修饰词有:assign.weak.strong.retain.co ...

  10. BZOJ2006:超级钢琴(ST表+堆求前K大区间和)

    Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度 ...