题意

小 \(\mathrm{C}\) 很喜欢二维染色问题,这天他拿来了一个 \(w × h\) 的二维平面 , 初始时均为白色 . 然后他在上面设置了 \(n\) 个关键点 \((X_i , Y_i)\) , 对于每个关键点他会选择进行下列操作的一个 :

  • 将 \(x > X_i\) 的部分染成黑色.
  • 将 \(x < X_i\) 的部分染成黑色.
  • 将 \(y > Y_i\) 的部分染成黑色.
  • 将 \(y < Y_i\) 的部分染成黑色.

现在让你 , 最大化所有操作结束之后白色部分的 周长 如果白色部分没有输出 \(0\)

\((0 \le n ≤ 2 \times 10^5 , 1 \le w,h \le 10^8, 0\le X_i \le w, 0 \le Y_i \le h)\)

题解

我先摘一段 dy0607 的题解qwq (Orz dyy)

题目实际上是要找一个周长最大的矩形 , 内部不包含任何关键点.

可以发现一个小性质 : 答案的下界为 \(2 × (max(w, h) + 1)\) ,

因此这个矩形一定会经过 \(x = \frac{w}{2}\) 或 \(y = \frac{h} {2}\) . 先考虑经过 \(x = \frac{w}{2}\) 的情况 , 另一种情况是一样的.

先将坐标离散化.枚举矩形的上边界 \(y_R\) ,对于每一个下边界 \(y_L\) , 我们可以计算出矩形的最优左边界 \(x_L = min \{X_i |Y_i ∈ [y_L , y_R ], X_i > \frac{w}{2} \}\) , 以 及 右 边 界 \(x_R = max \{X_i |Y_i ∈[y_L , y_R ], X_i ≤ \frac{w} {2} \}\) ,

此时可以找到一个周长为 \(2 × (x R − x L + y R − y L )\) 的矩形.

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

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

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

就算没有观察到上面的小性质,也可以多套一层分治解决,复杂度多一个 \(\log\) .

说的很轻松 其实很难理解

\(\Theta(n^2)\) 的算法 就是运用了那个小性质 每次枚举上边界 滑动的时候 一遍更新 一遍算下答案 就行了

我们主要是考虑 \(\Theta(n \log n)\) 的算法 , 如何理解呢 ...

其实我们就是枚举了一个上边界 , 然后对于这个上边界时 所有下边界的最优解都存在线段树中 .

(存的是当前 当前的顶到这里的宽 -下底界的高度 )


主要讲一下单调栈是干什么的

其中元素是一个个从栈底到栈顶是逐渐远离中线的线段 .

其中有两个维度 一个是维护这条线段的上端 , 另一个是维护这条线段的这条线段的横坐标 用来算和中线的长度 .

然后维护了这个有什么用呢 0.0 就是你考虑如下一种情况

(虚线为中线 黑色 是当前单调栈里的 红色 是现在将过来的一个线段)


我们现在要过来的线段 , 将会更新答案 .

所以我们将两个栈顶线段的答案进行更改 , 将这些线段的横着的答案变小它坐标的相应的差值.

这个就可以直接在线段树上做加减法就行了 .

然后我们用这条 绿色 和 红色 的线段一起 共同构成一个新的线段存进单调栈中去 .


记得前面线段树存的什么嘛 .

就是一个点当前宽与底坐标的差值 , 然后顶 (就是后一个线段的纵坐标) 又是固定的 那么我们用顶减去底 然后加上当前宽 .

就得到了当前矩形一半周长的最优答案 .


然后为了解决两个相邻直接当上下界的答案 , 我们每次结束要在单调栈中多加一个元素 (横坐标为边界) 就行了 .

然后坐标翻转再做一遍 就行了就是可能跨了另一条中线qwq

代码

代码比较巧妙 一定要对着理解!!

#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std; inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;} inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * fh;
} void File() {
freopen ("paint.in", "r", stdin);
freopen ("paint.out", "w", stdout);
} const int N = 200010; int w, h, n; struct Segment_Tree {
int maxv[N << 2], add[N << 2]; void Init() { Set(maxv, 0); Set(add, 0); } void Update(int o, int l, int r, int ul, int ur, int uv) {
if (ul <= l && r <= ur) { maxv[o] += uv; add[o] += uv; return ; }
int mid = (l + r) >> 1;
if (ul <= mid) Update(o << 1, l, mid, ul, ur, uv);
if (ur > mid) Update(o << 1 | 1, mid + 1, r, ul, ur, uv);
maxv[o] = max(maxv[o << 1], maxv[o << 1 | 1]) + add[o];
}
} T; typedef pair<int, int> PII;
#define x first
#define y second
#define mp make_pair
PII lt[N];
PII sta[N], stb[N];
int topa, topb; int ans = 0; void Work() {
sort(lt + 1, lt + 1 + n); T.Init();
topa = topb = 0; For (i, 1, n - 1) {
if (lt[i].y <= h / 2) {
int Next = i - 1;
while (topa && lt[i].y > sta[topa].y) {
T.Update(1, 1, n, sta[topa].x, Next, sta[topa].y - lt[i].y);
Next = sta[topa].x - 1; -- topa;
}
if (Next != i - 1) sta[++ topa] = mp(Next + 1, lt[i].y);
} else {
int Next = i - 1;
while (topb && lt[i].y < stb[topb].y) {
T.Update(1, 1, n, stb[topb].x, Next, lt[i].y - stb[topb].y);
Next = stb[topb].x - 1; -- topb;
}
if (Next != i - 1) stb[++ topb] = mp(Next + 1, lt[i].y);
}
sta[++ topa] = mp(i, 0);
stb[++ topb] = mp(i, h); T.Update(1, 1, n, i, i, h - lt[i].x);
chkmax(ans, T.maxv[1] + lt[i + 1].x);
}
} int main () {
File();
w = read(); h = read(); n = read();
For (i, 1, n) {
lt[i].x = read();
lt[i].y = read();
}
lt[++ n] = mp(0, 0);
lt[++ n] = mp(w, h);
Work(); For (i, 1, n)
swap(lt[i].x, lt[i].y);
swap(w, h);
Work(); printf ("%d\n", ans << 1);
return 0;
}

AtCoder Regular Contest 063 F : Snuke’s Coloring 2 (线段树 + 单调栈)的更多相关文章

  1. AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图

    AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图 链接 AtCoder 大意 在数轴上放上n个点,点i可能的位置有\(x_i\)或者\(y_i\ ...

  2. AtCoder Regular Contest 076 F - Exhausted?

    题意: n个人抢m个凳子,第i个人做的位置必须小于li或大于ri,问最少几个人坐不上. 这是一个二分图最大匹配的问题,hall定理可以用来求二分图最大匹配. 关于hall定理及证明,栋爷博客里有:ht ...

  3. AtCoder Regular Contest 082 F

    Problem Statement We have a sandglass consisting of two bulbs, bulb A and bulb B. These bulbs contai ...

  4. [Atcoder Regular Contest 063] Tutorial

    Link: ARC063 传送门 C: 将每种颜色的连续出现称为一段,寻找总段数即可 #include <bits/stdc++.h> using namespace std; ,len; ...

  5. Atcoder Regular Contest 066 F genocide【JZOJ5451】

    题目 分析 \(s[i]\)表示a前缀和. 设\(f[i]\)表示做完了1~i的友谊颗粒的最优值(不一定选i),那么转移方程为 \[f[i]=max\{f[i-1],max\{f[j]-s[i]+s[ ...

  6. AtCoder Regular Contest 068E:Snuke Line

    题目传送门:https://arc068.contest.atcoder.jp/tasks/arc068_c 题目翻译 直线上有\(0-m\)这\(m+1\)个点,一共有\(m\)辆火车.第\(i\) ...

  7. AtCoder Regular Contest 073 E:Ball Coloring

    题目传送门:https://arc073.contest.atcoder.jp/tasks/arc073_c 题目翻译 给你\(N\)个袋子,每个袋子里有俩白球,白球上写了数字.对于每一个袋子,你需要 ...

  8. AtCoder Regular Contest 063 E:Integers on a Tree

    题目传送门:https://arc063.contest.atcoder.jp/tasks/arc063_c 题目翻译 给你一个树,上面有\(k\)个点有权值,问你是否能把剩下的\(n-k\)个点全部 ...

  9. AtCoder Regular Contest 074 F - Lotus Leaves

    题目传送门:https://arc074.contest.atcoder.jp/tasks/arc074_d 题目大意: 给定一个\(H×W\)的网格图,o是可以踩踏的点,.是不可踩踏的点. 现有一人 ...

随机推荐

  1. Luogu4528 CTSC2008 图腾 树状数组、容斥

    传送门 设$f_i$表示$i$排列的数量,其中$x$表示不确定 那么$$ans=f_{1324}-f_{1432}-f_{1243}=(f_{1x2x}-f_{1423})-(f_{14xx}-f_{ ...

  2. 练习angularjs的ng-click的应用

    angular的click事件ng-click. 实现一个小功能计数器,用户可以点击“+”或“-”铵钮,数值每随点击铵钮增长1或减1.使用ng-init设置初始值为0. <div ng-app= ...

  3. Dell Technology Summit(2018.10.17)

    时间:2018.10.17地点:北京国家会议中心

  4. [Oracle]跨DBLINK的JOIN查询的数据库缓存问题15783452141

    客户问到跨DBLINK,结合本地表和远端表的时候,数据在哪一边 的 Data Buffer 缓存. 测试的结果是:本地表在本地缓存,远端表在远端缓存. ####Testcase-0929-10 本地数 ...

  5. assert_param函数的用法

    在STM32的固件库和提供的例程中,到处都可以见到assert_param()的使用.如果打开任何一个例程中的stm32f10x_conf.h文件,就可以看到实际上assert_param是一个宏定义 ...

  6. Oracle_安装问题

    [INS-07003] 访问 BeanStore 时出现意外错误   oracle安装时出现以下问题: 原因:未配置环境变量CLASSPASH 解决方法:新增系统变量,在我的电脑上右击-属性-高级系统 ...

  7. linux下日志文件error监控报警脚本分享

    即对日志文件中的error进行监控,当日志文件中出现error关键字时,即可报警!(grep -i error 不区分大小写进行搜索"error"关键字,但是会将包含error大小 ...

  8. Linux内核分析——第四章 进程调度

    第四章 进程调度 4.1 多任务 1.多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 2.多任务操作系统使多个进程处于堵塞或者睡眠状态,实际不被投入执行,这些任务尽管位于内存,但是并不处于 ...

  9. 冲刺Two之站立会议9

    今天我们团队主要针对软件的功能进行了改进.因为它目前可以实现视频通话,语音聊天,文件传输和文字聊天的通信功能,我们想要在它的基础上实现临时局域群聊和群聊视频的功能,目前还没有完全实现.

  10. 基于SSH的高校网上选课系统的质量属性的实现

    我对于基于SSH的高校网上选课系统的质量属性的实现是从可用性.性能.安全性.可维护性.易用性五个方面进行的实现. 可用性方面: 实现方式:(1)当系统试图超出限制范围来进行课程查询或选课时必须进行错误 ...