[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 ...
随机推荐
- 管中窥Vue
博客文章链接:管中窥Vue Vue和Angular.React.js的相同点和不同点? 与React的相同: 都使用了Virtual DOM 提供了响应式和组件化的视图组件 将注意力集中保持在核心库, ...
- SpringMVC ajax技术无刷新文件上传下载删除示例
参考 Spring MVC中上传文件实例 SpringMVC结合ajaxfileupload.js实现ajax无刷新文件上传 Spring MVC 文件上传下载 (FileOperateUtil.ja ...
- 科目三靠边停车难度升级,超过50cm不合格怎么破?
驾考新规实施了几天,考过的学员普遍反映科目三难度升级,其中靠边停车项目的扣分点细化之后,一不小心就会不合格.新规以前靠边停车不压线就好了,新规之后,车辆距离马路右侧边缘线超过50cm就要扣100分,对 ...
- .cxx_destruct crash
开发过程中遇到 YXTBaseLabelCell .cxx_destruct崩溃,查了下,会在调用类的dealloc方法时调用cxx_destruct,于是看了下代码,找dealloc可能会崩溃的原因 ...
- codeforces 702B B. Powers of Two(水题)
题目链接: B. Powers of Two time limit per test 3 seconds memory limit per test 256 megabytes input stand ...
- cygwin Could not create directory '/home/Administrator/.ssh'
在cygwin下运行: ssh-keygen -C "634772208@qq.com" -t rsa 时,出现如下错误: cygwin Could not create dire ...
- MongoDB复制集相关方法使用(五)
这里我们把复制集中可用的方法都实验一遍,帮助我们更好地来理解复制集.提前说明这些方法的使用是基于Mongodb3.2版本来的,看这篇文章之前需要先看上一篇文章. 介绍一下复制集可用的相关方法 rs.h ...
- Map容器线程安全问题
一.HashMap在非线程安全的环境下使用会出现什么样的问题? public class HashMapMultiThread { static Map<String,String> ma ...
- Gulp简单应用
1.创建一个工程,在webstorm控制台 cnpm install --save-dev gulp cnpm install --save-dev gulp-concat ...
- Docker运行MongoDB及Redis及ssh端口映射远程连接
Docker运行MongoDB及Redis及ssh端口映射远程连接 本节内容简介 在本实验里我们将通过完成 MongoDB 和 Redis 两个容器来学习Dockerfile及Docker的运行机制. ...