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 (线段树+单调栈)的更多相关文章

  1. Codeforces 781E Andryusha and Nervous Barriers 线段树 单调栈

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF781E.html 题目传送门 - CF781E 题意 有一个矩形,宽为 w ,高为 h .一开始会有 w 个 ...

  2. 洛谷P4425 转盘 [HNOI/AHOI2018] 线段树+单调栈

    正解:线段树+单调栈 解题报告: 传送门! 1551又是一道灵巧连题意都麻油看懂的题,,,,所以先解释一下题意好了,,,, 给定一个n元环 可以从0时刻开始从任一位置出发 每次可以选择向前走一步或者在 ...

  3. 线段树+单调栈+前缀和--2019icpc南昌网络赛I

    线段树+单调栈+前缀和--2019icpc南昌网络赛I Alice has a magic array. She suggests that the value of a interval is eq ...

  4. 牛客多校第四场sequence C (线段树+单调栈)

    牛客多校第四场sequence C (线段树+单调栈) 传送门:https://ac.nowcoder.com/acm/contest/884/C 题意: 求一个$\max {1 \leq l \le ...

  5. Codeforces 1175F - The Number of Subpermutations(线段树+单调栈+双针/分治+启发式优化)

    Codeforces 题面传送门 & 洛谷题面传送门 由于这场的 G 是道毒瘤题,蒟蒻切不动就只好来把这场的 F 水掉了 看到这样的设问没人想到这道题吗?那我就来发篇线段树+单调栈的做法. 首 ...

  6. [Codeforces1132G]Greedy Subsequences——线段树+单调栈

    题目链接: Codeforces1132G 题目大意:给定一个序列$a$,定义它的最长贪心严格上升子序列为$b$满足若$a_{i}$在$b$中则$a_{i}$之后第一个比它大的也在$b$中.给出一个数 ...

  7. BZOJ.4540.[HNOI2016]序列(莫队/前缀和/线段树 单调栈 RMQ)

    BZOJ 洛谷 ST表的一二维顺序一定要改过来. 改了就rank1了哈哈哈哈.自带小常数没办法. \(Description\) 给定长为\(n\)的序列\(A_i\).\(q\)次询问,每次给定\( ...

  8. AtCoder Regular Contest 063 F : Snuke’s Coloring 2 (线段树 + 单调栈)

    题意 小 \(\mathrm{C}\) 很喜欢二维染色问题,这天他拿来了一个 \(w × h\) 的二维平面 , 初始时均为白色 . 然后他在上面设置了 \(n\) 个关键点 \((X_i , Y_i ...

  9. 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< ...

随机推荐

  1. [2017BUAA软工助教]第0次作业小结

    BUAA软工第0次作业小结 零.题目 作业链接: This is a hyperlink 一.评分规则 本次作业满分10分: 按时提交有分 一周内补交得0分 超过一周不交或抄袭倒扣全部分数 评分规则如 ...

  2. 团队作业5——测试与发布(alpha阶段)

    Deadline: 2018-5-9 10:00PM,以提交至班级博客时间为准. 根据以下要求,完成对本团队项目的测试与发布. 测试 请根据团队项目中软件的需求文档.功能说明.系统设计和测试计划,写出 ...

  3. CentOS下配置SS5(SOCKS5)代理服务器

    方案:使用开源的SS5( Socks Server 5 ) 官网:http://ss5.sourceforge.net/ (点击左侧的Software在右侧的Server处进入下载地址) CentOs ...

  4. ipython安装( jupyter)

    生产环境:win10 64位 pip的版本不是最新的,输入命令 python -m pip install --upgrade pip 更新我们的pip,pip不是最新的也会导致安装不了ipython ...

  5. jdk下载及环境变量配置

    一.下载 下载链接 二.环境变量:

  6. IdentityServer4【QuickStart】之切换到混合流并且添加API访问

    切换到混合流并且添加API访问 前面的示例中我们开发了API访问和用户认证,现在我们要将两个合并到一起. OpenID Connect&OAuth 2.0组合的美妙之处是,你可以使用单一协议和 ...

  7. php trait使用

    trait类似于基类  同样的方法优先级为 本类>trait>基类 <?php /** * Created by PhpStorm. * User: mac * Date: 2019 ...

  8. 想在已创建的Vue工程里引入vux组件

    <1>. 在项目里安装vux npm install vux --save <2>. 安装vux-loader (这个vux文档似乎没介绍,当初没安装结果报了一堆错误) npm ...

  9. C# 中那些常用的工具类(Utility Class)(二)

    今天按照这一年来经常用到的那些静态的工具类再来做一次总结,这些小的工具来可以作为自己学习的很好的例子,通过总结这些东西,能够很大程度上梳理自己的知识体系,当然这个是经常用到的,接下来就一个个去分析这些 ...

  10. Spring Aop实例@Aspect、@Before、@AfterReturning@Around 注解方式配置

    用过spring框架进行开发的人,多多少少会使用过它的AOP功能,都知道有@Before.@Around和@After等advice.最近,为了实现项目中的输出日志和权限控制这两个需求,我也使用到了A ...