先将问题进行转化,发现满足\((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. 《Java核心技术》笔记:第7章 异常、断言和日志

    1. 异常 (P 280)异常处理需要考虑的问题: 用户输入错误 设备错误 物理限制 代码错误 (P 280)传统的处理错误的方法是:返回一个特殊的错误码,常见的是返回-1或者null引用 (P 28 ...

  2. 明文暴露___JS前台加密,java后台解密实现

    1.前台JS <script type="text/javascript"> $(function() { $("#btn").click(func ...

  3. java基础-8种基本类型

    正文 java中的八种基础类型. boolean:只有两个值,false,true 带符号类型 byte:占用1个字节,一个字节也就是8位,那么由于是最高一位是用来表示 负还是正,所以范围就是 -2^ ...

  4. 入门大数据---Map/Reduce,Yarn是什么?

    简单概括:Map/Reduce是分布式离线处理的一个框架. Yarn是Map/Reduce中的一个资源管理器. 一.图形说明下Map/Reduce结构: 官方示意图: 另外还可以参考这个: 流程介绍: ...

  5. 通用Mapper与分页插件的集成

    SpringBoot 是为了简化 Spring 应用的创建.运行.调试.部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖 ...

  6. Kubernetes实战总结 - Ingress选型与应用

    一.概述 Ingress 是对集群中服务的外部访问进行管理的 API 对象,可以提供负载均衡.SSL 终结和基于名称的虚拟托管. 典型的访问方式是 HTTP,用于将不同URL的访问请求转发到后端不同的 ...

  7. Django项目中集成第三方登录时出现的错误

    原以为是被反爬 没想到 总结:这里的http应该是https协议,以后要更加小心 了,不能犯这种低级错误

  8. mssql 手工注入流程小结

    对于MSSQL的注入点,无外乎这三种权限:SA,DB_OENER,PUBLIC.SA(System Admin)权限我们可以直接执行命令,DB_OENER权限的话,我们可以找到WEB的路径,然后用备份 ...

  9. java 和 c++ 的三目运算符的区别

    转载请注明出处:http://www.cnblogs.com/liangyongrui/p/6348001.html 以前很少用java,就知道java和c++差不多. 今天就踩了一个坑. 不吐糟,直 ...

  10. Kail安装VMtools

    0x00 前言 之前用吾爱的xp虚拟机,总是装不上vmtools,真是难受.每次跨机器粘贴复制都一件极其痛苦的事,而且虚拟机还不能直接浏览硬盘上的文件.虽说安全性保证了,但是这是真的痛苦.这两天开始用 ...