先将问题进行转化,发现满足\((max-min)-(r-l)=0\)的区间即为好区间。

对于本题这样的统计子区间的问题,先将询问离线,按右端点排序一个一个解决,固定右端点,然后通过数据结构来处理出区间信息,询问直接查询区间合法的贡献即可,扫一遍就能解决所有询问。

继续看这个式子\((max-min)-(r-l)=0\),发现如果去维护这个式子的值,对于固定的右端点,可以统计出其之前的左端点与该右端点的区间最小值及其个数,最小值个数即为在这个区间内可以对这个固定的右端点有贡献的左端点。

但这只能记录右端点固定的答案,无法处理子区间的问题,可以记录下历史最小值个数和,再进行询问即为这段区间的所有子区间的答案了。

具体实现时,维护\(max-min\)的变化可以通过单调栈来实现,\(r-l\)的变化直接对整个区间减一即可,历史最小值个数和需要通过打标记来看该区间是否能产生贡献,细节就看代码吧。

\(code:\)

#include<bits/stdc++.h>
#define maxn 500010
#define ls (cur<<1)
#define rs (cur<<1|1)
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,q,t1,t2,root=1;
int a[maxn],s1[maxn],s2[maxn];
ll ans[maxn],mi[maxn],cnt[maxn],sum[maxn],add[maxn],tag[maxn];
struct Query
{
int l,id;
};
vector<Query> ve[maxn];
void pushup(int cur)
{
ll lm=mi[ls],rm=mi[rs],lc=cnt[ls],rc=cnt[rs];
if(lm==rm) mi[cur]=lm,cnt[cur]=lc+rc;
if(lm<rm) mi[cur]=lm,cnt[cur]=lc;
if(lm>rm) mi[cur]=rm,cnt[cur]=rc;
sum[cur]=sum[ls]+sum[rs];
}
void pushadd(int cur,ll v)
{
mi[cur]+=v,add[cur]+=v;
}
void pushtag(int cur,ll v)
{
sum[cur]+=cnt[cur]*v,tag[cur]+=v;
}
void pushdown(int cur)
{
if(add[cur])
pushadd(ls,add[cur]),pushadd(rs,add[cur]),add[cur]=0;
if(tag[cur])
{
if(mi[cur]==mi[ls]) pushtag(ls,tag[cur]);
if(mi[cur]==mi[rs]) pushtag(rs,tag[cur]);
tag[cur]=0;
}
}
void build(int l,int r,int cur)
{
if(l==r)
{
mi[cur]=l,cnt[cur]=1;
return;
}
build(l,mid,ls),build(mid+1,r,rs);
pushup(cur);
}
void modify(int L,int R,int l,int r,ll v,int cur)
{
if(L<=l&&R>=r)
{
pushadd(cur,v);
return;
}
pushdown(cur);
if(L<=mid) modify(L,R,l,mid,v,ls);
if(R>mid) modify(L,R,mid+1,r,v,rs);
pushup(cur);
}
ll query(int L,int R,int l,int r,int cur)
{
if(L<=l&&R>=r) return sum[cur];
pushdown(cur);
ll ans=0;
if(L<=mid) ans+=query(L,R,l,mid,ls);
if(R>mid) ans+=query(L,R,mid+1,r,rs);
return ans;
}
int main()
{
read(n),build(1,n,root);
for(int i=1;i<=n;++i) read(a[i]);
read(q);
for(int i=1;i<=q;++i)
{
int l,r;
read(l),read(r);
ve[r].push_back((Query){l,i});
}
for(int i=1;i<=n;++i)
{
while(t1&&a[s1[t1]]<=a[i])
{
modify(s1[t1-1]+1,s1[t1],1,n,a[i]-a[s1[t1]],root);
t1--;
}
while(t2&&a[s2[t2]]>=a[i])
{
modify(s2[t2-1]+1,s2[t2],1,n,a[s2[t2]]-a[i],root);
t2--;
}
s1[++t1]=s2[++t2]=i,pushadd(root,-1),pushtag(root,1);
int size=ve[i].size();
for(int j=0;j<size;++j)
ans[ve[i][j].id]=query(ve[i][j].l,i,1,n,root);
}
for(int i=1;i<=q;++i) printf("%lld\n",ans[i]);
return 0;
}

题解 CF997E 【Good Subsegments】的更多相关文章

  1. [cf997E]Good Subsegments

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

  2. 「CF997E」 Good Subsegments

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

  3. CF 997E 解题报告

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

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

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

  5. 【Codeforces Round】 #431 (Div. 2) 题解

    Codeforces Round #431 (Div. 2)  A. Odds and Ends time limit per test 1 second memory limit per test ...

  6. CoderForces Round60-(1117A,1117B,1117C题解)

    A. Best Subsegment time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  7. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  8. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  9. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

随机推荐

  1. vue开发搭建(npm安装 + vue脚手架安装)

    一.概念 1.npm:  Nodejs下的包管理器. 2.webpack: 它主要的用途是通过CommonJS的语法,把所有浏览器端需要发布的静态资源,做相应的准备,比如资源的合并和打包. 3.vue ...

  2. 黎活明8天快速掌握android视频教程--27_网络通信之通过GET和POST方式提交参数给web应用

    1该项目主要实现Android客户端以get的方式或者post的方式向java web服务器提交参数 Android客户端通过get方式或者post方式将参数提交给后台服务器,后台服务器对收到的参数进 ...

  3. linux中神奇的命令alias

    在linux中大家应该都知道,有些命令和参数特别繁琐,而且还是大量输入这些命令,这个时候我们就可以使用linux中的alias命令来给这些繁琐的命令起别名,但是,alias 命令只对当前终端有效,当终 ...

  4. Python 简明教程 ---10,Python 列表

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 程序 = 算法 + 数据结构 -- Nicklaus Wirth 目录 从这句话程序 = 算法 + ...

  5. LQR算法如何跟随变化的期望状态

    开门见山,通过LQR的能量函数可以看出,LQR算法是将状态量控制到零(关于能量函数请看我的随笔:LQR要点),但实际控制中我们希望状态量能够跟随期望值 下面将会解决如何用LQR算法跟随变化的期望值: ...

  6. Python实用笔记——错误处理

    让我们用一个例子来看看try的机制: try: print('try...') r = 10 / 0 print('result:', r) except ZeroDivisionError as e ...

  7. Markdown-it-latex2img

    Markdown-it-latex2img LaTex plugin for markdown-it markdown parser,Server side MathJax Renderer. Bac ...

  8. 前端JS 下载大文件解决方案

    问题场景 点击导出按钮,提交请求,下载excel大文件(超过500M),该文件没有预生成在后端, 直接以文件流的形式返回给前端. 解决方案 在Vue项目中常用的方式是通过axios配置请求,读取后端返 ...

  9. 小师妹学JVM之:JIT中的PrintAssembly续集

    目录 简介 JDK8和JDK14中的PrintAssembly JDK8中使用Assembly JDK14中的Assembly 在JMH中使用Assembly 总结 简介 上篇文章和小师妹一起介绍了P ...

  10. 作为架构师必须知道的Netty原理和使用

    本文首发于微信公众号[猿灯塔],转载引用请说明出处 今天呢!灯塔君跟大家讲: Netty应用 一.Netty简介 1.Netty下载 官网:https://netty.io/downloads.htm ...