[arc063]F.すぬけ君の塗り絵2
因为这题考虑可以观察一个性质,答案的下界为 \(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的更多相关文章
- ARC063F すぬけ君の塗り絵 2 / Snuke's Coloring 2
题面 一句话题面:给你一些点,求这些点之中夹的最大的矩形周长.(考虑边界) Solution 首先是一个结论,答案矩形一定经过\(x=\frac{w}{2}\)或经过\(y=\frac{h}{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. ...
- 【AtCoder】ARC063
ARC063 C - 一次元リバーシ / 1D Reversi 不同的颜色段数-1 #include <bits/stdc++.h> #define fi first #define se ...
- 【AtCoder】ARC061
ARC061 C - たくさんの数式 / Many Formulas 这个其实\(10^5\)也能做.. 就是\(dp[i]\)表示到第i位的方案数,\(sum[i]\)表示延伸到第i位之前的所有方案 ...
- DP题组
按照顺序来. Median Sum 大意: 给你一个集合,求其所有非空子集的权值的中位数. 某集合的权值即为其元素之和. 1 <= n <= 2000 解: 集合配对,每个集合都配对它的补 ...
- csp退役前的做题计划1(真)
csp退役前的做题计划1(真) 因为我太菜了,所以在第一次月考就会退役,还是记录一下每天做了什么题目吧. 任务计划 [ ] Z算法(Z Algorithm) 9.28 [x] ARC061C たくさん ...
- es6 解构赋值
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 关于给变量赋值,传统的变量赋值是这样的: var arr = [1,2,3];//把数组的值 ...
- php debug二三事
最近php相关项目遇到了一些问题,处理起来让人感觉挺有意思,寥寥记下. 1.php执行后常驻内存里,需要kill掉该进程再重启,才能让修改后的代码生效. 之前有一次组里小伙伴修改了一个长期后台进程运行 ...
- Unicode字符集的由来
*:first-child { margin-top: 0 !important; } .markdown-body>*:last-child { margin-bottom: 0 !impor ...
随机推荐
- Fastjson 简介
Fastjson is a Java library that can be used to convert Java Objects into their JSON representation. ...
- (linux)idr(integer ID management)机制
最近研究进程间通信,遇到了idr相关的函数,为了扫清障碍,先研究了linux的idr机制. IDR(integer ID management)的要完成的任务是给要管理的对象分配一个唯一的ID,于 ...
- ALSA lib调用实例
1. Display Some PCM Types and Formats 2. Opening PCM Device and Setting Parameters /* This example o ...
- codeforces 463A Caisa and Sugar 解题报告
题目链接:http://codeforces.com/problemset/problem/463/A 题目意思:某个人有 s dollar的钱,有 n 种类型的糖果,第 i 种糖果的价值为 xi d ...
- css元素定位样式
曾经写网页,学css整体上不难,但就是元素定位,始终一知半解,直到今天,本着实践出真知的理念,经过认真测试,总结出了如下结论. css 定位: positionstatic : 默认静止定位,元素在正 ...
- JQ里的this与$(this)
网上有很多关于jQuery的this和$(this)的介绍,大多数只是理清了this和$(this)的指向,其实它是有应用场所的,不能一概而论在jQuery调用成员函数时,this就是指向dom对象. ...
- emacs设置tab缩进
这两天使用Emacs自带的JavaScriptMode时,发现与其它编辑器下缩进不同,而且用emacs重新缩进对齐后,再用其它的编辑器打时缩进却乱掉了.分析应该是Tab缩进的问题,在.emacs中增加 ...
- [转载]Dalvik指令集
这篇文章是转载的,为了便于查找一些指令,贴在这里. 转自:http://blog.csdn.net/canfengxiliu/article/details/20144119 ------------ ...
- 属性(@property)的修饰词有哪些,各自是什么作用,在哪种情况下用?
之前面试了几家公司,都会问到这个基础的问题,以前,没有怎么注意,所以答的很混乱,所以查了查网上的资料,特意整理了一份. 常见修饰词有:assign.weak.strong.retain.co ...
- BZOJ2006:超级钢琴(ST表+堆求前K大区间和)
Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度 ...