Description

Transmission Gate

给你一个长度为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≤n,q≤1.2×10^5\).

Solution

可以发现,区间\([l,r]\)是好的,当且仅当$ (Max - Min)=(r−l) $,考虑维护一段区间上式的最小值。

考虑固定右端点时,子区间的个数。每一个最小值为0的位置都可以和当前的r组成一个好的区间。

不难发现,一个右端点能产生的贡献为它左边的点的最小值为0的个数,于是可以在线段树上维护最小值和最小值个数,以及每个最小值为0的位置产生的贡献。

由于右边新加的点会对已有的点产生影响,考虑离线询问,按右端点排序,用两个单调栈分别维护当前Min和Max。右端点右移时,整个区间的值都会减一,又因为处理子区间,所以当右端点右移时我们必须统计当前的答案,也就是历史最小值个数。时间复杂度\(O(n \times log_2^n)\)

在下传标记时,因为之前的统计标记还未下传到当前点,所以我们不能判断当\(Min_{root} == 0\)时才计算贡献,而是当$ Min_{fa[root]} == Min_{root} $时才统计。 因为当前节点一旦被打了标记就代表出现过了最小值为0的情况。

这里我们可以总结出一个套路,就是当我们要统计一个节点的所有子区间的答案时,可以先行离线从小到大统计固定右端点的答案,然后移动右端点时再统计历史值。

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for(int i = (j), i##_end_ = (k); i <= i##_end_; ++i)
#define drep(i, j, k) for(int i = (j), i##_end_ = (k); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(s, ...) fprintf(stderr, s, __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(LL x) {
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar(x % 10 + 48);
} #define Maxn 120009
struct Quer {
int l, id;
};
vector <Quer> s[Maxn];
int n, a[Maxn], q, stk1[Maxn], stk2[Maxn], top1, top2;
LL ans[Maxn];
namespace SGMT_tree {
int tree[Maxn << 2], cnt[Maxn << 2], add[Maxn << 2], Time[Maxn << 2];
LL Sum[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 setAdd(int rt, int val) {
tree[rt] += val;
add[rt] += val;
}
void setTime(int rt, int val) {
Sum[rt] += 1ll * cnt[rt] * val;
Time[rt] += val;
}
void (*setTag)(int, int);
void set(int dir) {
if(dir == 1) setTag = setAdd;
if(dir == 2) setTag = setTime;
}
void pushdown(int rt, int l, int r) {
if(add[rt]) {
setAdd(lc(rt), add[rt]), setAdd(rc(rt), add[rt]);
add[rt] = 0;
}
if(Time[rt]) {
if(tree[rt] == tree[lc(rt)]) setTime(lc(rt), Time[rt]);
if(tree[rt] == tree[rc(rt)]) setTime(rc(rt), Time[rt]);
Time[rt] = 0;
}
}
void pushup(int rt) {
cnt[rt] = 0;
tree[rt] = min(tree[lc(rt)], tree[rc(rt)]);
if(tree[rt] == tree[lc(rt)]) cnt[rt] += cnt[lc(rt)];
if(tree[rt] == tree[rc(rt)]) cnt[rt] += cnt[rc(rt)];
Sum[rt] = Sum[lc(rt)] + Sum[rc(rt)];
}
void build(int rt, int l, int r) {
tree[rt] = l; cnt[rt] = 1;
if(l == r) return ;
int mid = (l + r) >> 1;
build(ls), build(rs);
pushup(rt);
}
void modify(int rt, int l, int r, int x, int y, int val) {
if(x <= l && r <= y) {
setTag(rt, val);
return ;
}
int mid = (l + r) >> 1;
pushdown(rt, l, r);
if(y <= mid) modify(ls, x, y, val);
else if(x >= mid + 1) modify(rs, x, y, val);
else modify(ls, x, y, val), modify(rs, x, y, val);
pushup(rt);
}
LL query(int rt, int l, int r, int x, int y) {
if(x <= l && r <= y) return Sum[rt];
pushdown(rt, l, r);
int mid = (l + r) >> 1; LL res = 0;
if(x <= mid) res += query(ls, x, y);
if(y >= mid + 1) res += query(rs, x, y);
return res;
}
#undef lc
#undef rc
#undef ls
#undef rs
}
namespace INIT {
void Main() {
n = read();
rep(i, 1, n) a[i] = read();
q = read();
rep(i, 1, q) {
int l = read(), r = read();
s[r].push_back((Quer){l, i});
}
}
}
namespace SOLVE {
void Main() {
SGMT_tree :: build(1, 1, n);
rep(i, 1, n) {
SGMT_tree :: set(1);
SGMT_tree :: modify(1, 1, n, 1, n, -1);
for(SGMT_tree :: set(1); top1 && a[stk1[top1]] < a[i]; --top1)
SGMT_tree :: modify(1, 1, n, stk1[top1 - 1] + 1, stk1[top1], a[i] - a[stk1[top1]]);
stk1[++top1] = i;
for(SGMT_tree :: set(1); top2 && a[stk2[top2]] > a[i]; --top2)
SGMT_tree :: modify(1, 1, n, stk2[top2 - 1] + 1, stk2[top2],a[stk2[top2]] - a[i]);
stk2[++top2] = i;
SGMT_tree :: set(2);
SGMT_tree :: modify(1, 1, n, 1, n, 1);
rep(j, 0, s[i].size() - 1)
ans[s[i][j].id] = SGMT_tree :: query(1, 1, n, s[i][j].l, i);
}
rep(i, 1, q) write(ans[i]), putchar('\n');
}
}
int main() {
#ifdef Qrsikno
freopen("CF997E.in", "r", stdin);
freopen("CF997E.out", "w", stdout);
#endif
INIT :: Main();
SOLVE :: Main();
return 0;
}

[CF997E] Good SubSegment的更多相关文章

  1. 【CF997E】Good Subsegments (线段树+单调栈)

    Description 原题链接 给你一个长度为\(n\)的排列\(~P\),定义一段子区间是好的,当且仅当这个子区间内的值构成了连续的一段.例如对于排列\(\{1,3,2 \}\),\([1, 1] ...

  2. [CC-SEINC]Sereja and Subsegment Increasings

    [CC-SEINC]Sereja and Subsegment Increasings 题目大意: 有长度为\(n(n\le10^5)\)的序列\(A\)和\(B\). 在一次操作中,可以选择一个区间 ...

  3. CF1117A Best Subsegment

    CF1117A Best Subsegment 乍一看好像很难,仔细想一下发现就是弱智题... 任意一段平均数显然不会超过最大的数,若只取最大数即可达到平均数为最大数. 于是只用取最长的一段连续的最大 ...

  4. 「CF997E」 Good Subsegments

    CF997E Good Subsegments 传送门 和 CF526F 差不多,只不过这道题是对多个子区间进行询问. 据说有一个叫析合树的东西可以在线做,不过有时间再说吧. 考虑离线询问,将每个询问 ...

  5. 题解 CF997E 【Good Subsegments】

    先将问题进行转化,发现满足\((max-min)-(r-l)=0\)的区间即为好区间. 对于本题这样的统计子区间的问题,先将询问离线,按右端点排序一个一个解决,固定右端点,然后通过数据结构来处理出区间 ...

  6. [cf997E]Good Subsegments

    一个区间为好区间当且仅当$\max_{l\le i\le r}a_{i}-\min_{l\le i\le r}a_{i}=r-l$,考虑固定右端点$r$,维护所有左端点$l$的上述式子左-右的值,那么 ...

  7. CF724D. Dense Subsequence[贪心 字典序!]

    D. Dense Subsequence time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  8. Codeforces Round #369 (Div. 2)---C - Coloring Trees (很妙的DP题)

    题目链接 http://codeforces.com/contest/711/problem/C Description ZS the Coder and Chris the Baboon has a ...

  9. Codeforces Round #227 (Div. 2) E. George and Cards set内二分+树状数组

    E. George and Cards   George is a cat, so he loves playing very much. Vitaly put n cards in a row in ...

随机推荐

  1. jenkins修改日志级别方法

    1.jenkins日志有时候也会消耗掉很大内存,在传输时也会消耗掉大量带宽,如图,300+M的日志大小,太夸张了吧 2.修改日志级别的方法: 在配置文件里修改,重启后永久生效,配置路径:/etc/sy ...

  2. 全文搜索引擎 Elasticsearch 安装

    全文搜索引擎 Elasticsearch 安装 学习了:http://www.ruanyifeng.com/blog/2017/08/elasticsearch.html 拼音:https://www ...

  3. win8 metro 自己写摄像头录像项目

    这是要求不适用CameraCaptureUI等使用系统自带的 camera  UI界面.要求我们自己写调用摄像头摄像的方法,如今我把我的程序贴下: UI界面的程序: <Page x:Class= ...

  4. 在matlab中生成m序列

    实验环境为matlab2013b 1.首先编写一个mseq.m文件,内容为: function[mseq]=m_sequence(fbconnection)  n=length(fbconnectio ...

  5. 使用 Vagrant 构建开发环境

    使用 Vagrant 构建开发环境 摘要:本文描述了如使用 Vagrant 构建统一的开发环境. 问题 作为开发人员,我们通常面临的问题有: 开发环境需要手工安装配置,这包括操作系统(CentOS.U ...

  6. 使用 C# 开发智能手机软件:推箱子(三)

    这是"使用 C# 开发智能手机软件:推箱子"系列文章的第三篇.在这篇文章中,介绍 Common/Block.cs 源程序文件.   1 namespace Skyiv.Ben.Pu ...

  7. python 线程 进程 标识

    s = '%s%s%s%s%s%s%s%s' % ( time.strftime('%Y%m%d %H:%M:%S', time.localtime(time.time())), ' os.getpp ...

  8. hdu4908 &amp; BestCoder Round #3 BestCoder Sequence(组合数学)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4908 BestCoder Sequence Time Limit: 2000/1000 MS (Jav ...

  9. 使用ADO.NET对SQL Server数据库进行訪问

    在上一篇博客中我们给大家简介了一下VB.NET语言的一些情况,至于理论知识的学习我们能够利用VB的知识体系为基础.再将面向对象程序设计语言的知识进行融合便可进行编程实战. 假设我们须要訪问一个企业关系 ...

  10. xcode 8.1 (8B62)真机调试配置

    1.点击菜单栏中的Xcode->Preferences->Accounts,如图: 点击上图左下角中的“+”号,登陆一个Apple id(前提已经有了一个apple id账号), 2.然后 ...