【CF997E】Good Subsegments (线段树+单调栈)
Description
原题链接
给你一个长度为\(n\)的排列\(~P\),定义一段子区间是好的,当且仅当这个子区间内的值构成了连续的一段。例如对于排列\(\{1,3,2 \}\),\([1, 1], [2, 2], [3, 3], [2, 3], [1, 3]\)是好的区间。
共\(q\)次询问,每次询问\(L,R\), 求有多少\(L \leq l \leq r \leq R\),满足\([l, r]\)是好的区间。\(1 \leq n, q \leq 1.2 \times 10 ^ 5\).
Solution
可以发现,区间\([l, r]\)是好的,当且仅当\(~(Max_{i = l}^{r} - Min_{i = l} ^ {r}) - (r - l) = 0\).
考虑维护一段区间上式的最小值(以下的最小值都指上式最小值),每一个最小值为\(0\)的位置都可以和当前的\(r\)组成一个好的区间。不难发现,一个右端点能产生的贡献为它左边的点的最小值为\(0\)的个数,于是可以在线段树上维护最小值和最小值个数,以及每个最小值为\(0\)的位置产生的贡献。
由于右边新加的点会对已有的点产生影响,考虑离线询问,按右端点排序,用两个单调栈分别维护当前\(Min\)和\(Max\)。右端点右移时,势必会使整个区间的最小值减一,也势必会使其未右移前的右端点对答案产生一轮贡献,每次处理右端点等于当前枚举点的答案。时间复杂度\(O(n \log n)\).
Code
#include <bits/stdc++.h>
#define For(i, j, k) for (int i = j; i <= k; ++ i)
#define Forr(i, j, k) for (int i = j; i >= k; -- i)
using namespace std;
typedef long long ll;
inline int read() {
int x = 0, p = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') p = -1;
for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * p;
}
inline void File() {
freopen("CF997E.in", "r", stdin);
freopen("CF997E.out", "w", stdout);
}
const int N = 1.2e5 + 10;
int n, q, a[N], s1[N], t1, s2[N], t2, tt = 1; ll ans[N];
struct Query {
int id, l, r;
bool operator < (const Query &rhs) const { return r < rhs.r; }
} Q[N];
namespace Segment_Tree {
#define lc (rt << 1)
#define rc (rt << 1 | 1)
#define mid (l + r >> 1)
const int MAXN = N << 2;
int mn[MAXN], tag[MAXN], t[MAXN]; ll sum[MAXN], tg[MAXN];
inline void pushdown(int rt) {
if (tag[rt]) {
mn[lc] += tag[rt], mn[rc] += tag[rt];
tag[lc] += tag[rt], tag[rc] += tag[rt];
tag[rt] = 0;
}
if (tg[rt]) {
if (mn[lc] == mn[rt]) sum[lc] += 1ll * t[lc] * tg[rt], tg[lc] += tg[rt];
if (mn[rc] == mn[rt]) sum[rc] += 1ll * t[rc] * tg[rt], tg[rc] += tg[rt];
tg[rt] = 0;
}
}
inline void pushup(int rt) {
t[rt] = 0, mn[rt] = min(mn[lc], mn[rc]);
t[rt] = mn[rt] == mn[lc] ? t[rt] + t[lc] : t[rt];
t[rt] = mn[rt] == mn[rc] ? t[rt] + t[rc] : t[rt];
sum[rt] = sum[lc] + sum[rc];
}
inline void Build(int rt, int l, int r) {
mn[rt] = l, t[rt] = 1;
if (l ^ r) Build(lc, l, mid), Build(rc, mid + 1, r);
}
inline void update(int rt, int l, int r, int L, int R, int v) {
if (L <= l && r <= R) { mn[rt] += v, tag[rt] += v; return ; }
pushdown(rt); if (L <= mid) update(lc, l, mid, L, R, v);
if (R > mid) update(rc, mid + 1, r, L, R, v); pushup(rt);
}
inline ll query(int rt, int l, int r, int L, int R) {
if (L <= l && r <= R) return sum[rt]; pushdown(rt);
if (R <= mid) return query(lc, l, mid, L, R);
if (L > mid) return query(rc, mid + 1, r, L, R);
return query(lc, l, mid, L, R) + query(rc, mid + 1, r, L, R);
}
#undef lc
#undef rc
#undef mid
}
int main() {
File();
using namespace Segment_Tree;
n = read(); For(i, 1, n) a[i] = read();
q = read(); For(i, 1, q) Q[i].l = read(), Q[i].r = read(), Q[i].id = i;
sort(Q + 1, Q + 1 + q);
Build(1, 1, n);
For(nr, 1, n) {
mn[1] -= 1, tag[1] -= 1;
for (; t1 && a[s1[t1]] < a[nr]; -- t1)
update(1, 1, n, s1[t1 - 1] + 1, s1[t1], a[nr] - a[s1[t1]]);
s1[++ t1] = nr;
for (; t2 && a[s2[t2]] > a[nr]; -- t2)
update(1, 1, n, s2[t2 - 1] + 1, s2[t2], a[s2[t2]] - a[nr]);
s2[++ t2] = nr;
sum[1] += t[1], tg[1] += 1;
for (; tt <= q && Q[tt].r == nr; ++ tt)
ans[Q[tt].id] = query(1, 1, n, Q[tt].l, nr);
}
For(i, 1, q) printf("%lld\n", ans[i]);
return 0;
}
【CF997E】Good Subsegments (线段树+单调栈)的更多相关文章
- Codeforces 781E Andryusha and Nervous Barriers 线段树 单调栈
原文链接https://www.cnblogs.com/zhouzhendong/p/CF781E.html 题目传送门 - CF781E 题意 有一个矩形,宽为 w ,高为 h .一开始会有 w 个 ...
- 洛谷P4425 转盘 [HNOI/AHOI2018] 线段树+单调栈
正解:线段树+单调栈 解题报告: 传送门! 1551又是一道灵巧连题意都麻油看懂的题,,,,所以先解释一下题意好了,,,, 给定一个n元环 可以从0时刻开始从任一位置出发 每次可以选择向前走一步或者在 ...
- 线段树+单调栈+前缀和--2019icpc南昌网络赛I
线段树+单调栈+前缀和--2019icpc南昌网络赛I Alice has a magic array. She suggests that the value of a interval is eq ...
- 牛客多校第四场sequence C (线段树+单调栈)
牛客多校第四场sequence C (线段树+单调栈) 传送门:https://ac.nowcoder.com/acm/contest/884/C 题意: 求一个$\max {1 \leq l \le ...
- Codeforces 1175F - The Number of Subpermutations(线段树+单调栈+双针/分治+启发式优化)
Codeforces 题面传送门 & 洛谷题面传送门 由于这场的 G 是道毒瘤题,蒟蒻切不动就只好来把这场的 F 水掉了 看到这样的设问没人想到这道题吗?那我就来发篇线段树+单调栈的做法. 首 ...
- [Codeforces1132G]Greedy Subsequences——线段树+单调栈
题目链接: Codeforces1132G 题目大意:给定一个序列$a$,定义它的最长贪心严格上升子序列为$b$满足若$a_{i}$在$b$中则$a_{i}$之后第一个比它大的也在$b$中.给出一个数 ...
- BZOJ.4540.[HNOI2016]序列(莫队/前缀和/线段树 单调栈 RMQ)
BZOJ 洛谷 ST表的一二维顺序一定要改过来. 改了就rank1了哈哈哈哈.自带小常数没办法. \(Description\) 给定长为\(n\)的序列\(A_i\).\(q\)次询问,每次给定\( ...
- AtCoder Regular Contest 063 F : Snuke’s Coloring 2 (线段树 + 单调栈)
题意 小 \(\mathrm{C}\) 很喜欢二维染色问题,这天他拿来了一个 \(w × h\) 的二维平面 , 初始时均为白色 . 然后他在上面设置了 \(n\) 个关键点 \((X_i , Y_i ...
- cdqz2017-test10-rehearsal(CDQ分治&可持久化线段树&单调栈)
题意: 给出n个三元组 e[i]=(si,ti,wi) 第i个三元组的价值为 Σ w[j] ,j 满足以下4个条件: 1.j<i 2.tj<ti 3.sj<si 4.不存在j< ...
随机推荐
- Selling Souvenirs CodeForces - 808E (分类排序后DP+贪心)
E. Selling Souvenirs time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- 如何优化Docker储存
大家在使用Docker的过程中,有没有想过,Docker在本地存储镜像时把文件存储在哪里了呢?有没有对文件的总大小做一定的限制呢?能不能调整本地存储的位置及总限制大小呢?今天,我们就从这些问题入手,来 ...
- 线程中的samaphore信号量及event事件
一.信号量 samaphore: 在程序中意思为同时允许几个线程运行,比如我们去水上乐园的滑梯玩时,有四个滑梯,每一个滑梯上当没有人在中间玩滑下去时才允许上人,四个滑梯1,2,3,4,同时最多四个人, ...
- Oracle 序列(sequence)
序列(sequence) 是Oracle提供的用于生成一系列唯一数字的数据库对象.它会自动生成顺序递增或者递减的序列号,以实现自动提供唯一的主键值.序列可以在多用户并发环境中使用,并且可以为所有用户生 ...
- [转帖]NotePad++编辑Linux中的文件
NotePad++编辑Linux中的文件 https://blog.csdn.net/chengqiuming/article/details/78882692 原作者 未经允许不允许转帖 加密自己参 ...
- 【Java编译】含package的类文件编译
含package的类文件编译: package com.zhangxueliang.setdemo; public class Demo1 { public static void main(Stri ...
- Swagger2常用注解及其说明 (转)
Api 用在Controller中,标记一个Controller作为swagger的文档资源 属性名称 说明 value Controller的注解 description 对api资源的描述 hid ...
- Linux基础学习(16)--备份与恢复
第十六章——备份与恢复 一.备份概述 1.Linux系统需要备份的数据: 2.备份策略: 二.dump和restore命令 1.dump命令: 2.restore命令:
- sqlmap-学习1 配置环境
sqlmap是一款非常强大的开源sql自动化注入工具,可以用来检测和利用sql注入漏洞.它由python语言开发而成,因此运行需要安装python环境 1 安装 python (https://www ...
- static类型的变量
c语言中变量的储存类型有以下四种 auto 如果没有定义储存类型 默认就是这个类型 比如 int a = 10; 储存类型就是 auto:编译器会跟你定义的位置,以及用途,自动帮你决定使用那 ...