题意

给定一个序列,定义连续区间为区间的数排序后,任意两个相邻的数之差不超过1。

分析

  • 假设区间最大值为\(max\),最小值为\(min\),不同数个数为\(cnt\),那么问题转化为求满足\(max-min-cnt==1\)的区间个数。
  • 统计满足条件的区间个数可以考虑用线段树,主要有三个步骤:
    • 枚举右端点\(R\)
    • 线段树维护当前所有左端点,即每个叶子节点\((i,i)\),表示序列区间\([i,R]\)
    • 统计答案,以\(R\)为右端点的所有区间,即线段树根节点\((1,n)\)
  • 更新区间分为两部分
    • 第一部分是\(cnt\),也相当于也就是要更新当前\(R\),前面有多少个区间\([i,R]\)以\(a[R]\)作为一个新的不同的数字,显然就是\(a[R]\)上一次出现的位置+1,因为公式中是\(-cnt\),所以更新值为-1。
    • 第二部分是\(max\)和\(min\),利用单调栈来维护,当从栈中弹出时,可以得到该元素作为最大/最小值延伸的区间,更新值就是该元素和新的最大/最小值\(a[R]\)之间的差值。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+50;
const int INF=0x3f3f3f3f;
int T,n,a[N];
//线段树(1-n)维护的是当前R作为右端点,([1,R],[2,R]...[R,R])这些区间的情况,也就是一个点代表一个区间
struct ST{
#define ls i<<1
#define rs i<<1|1
#define mid (l+r)/2
//维护区间(mx-mn-cnt)的最小值和最小值的个数
int sm[N*4],mn[N*4],lz[N*4];
void pushup(int i){
mn[i]=min(mn[ls],mn[rs]);
if(mn[ls]==mn[rs]){
sm[i]=sm[ls]+sm[rs];
}else if(mn[ls]<mn[rs]){
sm[i]=sm[ls];
}else{
sm[i]=sm[rs];
}
}
void pushdown(int i){
if(lz[i]){
lz[ls]+=lz[i];
lz[rs]+=lz[i];
mn[ls]+=lz[i];
mn[rs]+=lz[i];
lz[i]=0;
}
}
void build(int i,int l,int r){
lz[i]=0;
if(l==r){
mn[i]=INF;
sm[i]=0;
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(i);
}
//单点插入/修改,即开始增加以p为左端点的区间贡献
void insert(int i,int l,int r,int p){
if(l==r){
//此时以p为左端点的区间只有[p,p],因此mx-mn-cnt=-1,为合法区间
mn[i]=-1;
sm[i]=1;
return;
}
pushdown(i);
if(p<=mid){
insert(ls,l,mid,p);
}else{
insert(rs,mid+1,r,p);
}
pushup(i);
}
//区间更新(mx-mn-cnt)
void update(int i,int l,int r,int ql,int qr,int v){
if(ql<=l && qr>=r){
lz[i]+=v;
mn[i]+=v;
return;
}
pushdown(i);
if(ql<=mid){
update(ls,l,mid,ql,qr,v);
}
if(qr>mid){
update(rs,mid+1,r,ql,qr,v);
}
pushup(i);
}
}ac;
map<int,int> lst;
int smx[N],smn[N];
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&T);
for(int cas=1;cas<=T;cas++){
ll ans=0;
scanf("%d",&n);
ac.build(1,1,n);
lst.clear();
int mxt=0,mnt=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ac.insert(1,1,n,i);
//单调栈维护最大最小值区间
//维护一个小顶栈,那么弹出来的元素作为最大值延伸的位置是[smx[mxt-1]+1,smx[mxt]]
while(mxt>0 && a[smx[mxt]]<=a[i]){
ac.update(1,1,n,smx[mxt-1]+1,smx[mxt],a[i]-a[smx[mxt]]);
mxt--;
}
smx[++mxt]=i;
while(mnt>0 && a[smn[mnt]]>=a[i]){
ac.update(1,1,n,smn[mnt-1]+1,smn[mnt],-(a[i]-a[smn[mnt]]));
mnt--;
}
smn[++mnt]=i;
//map维护上一次出现位置
int L=0;
if(lst.find(a[i])!=lst.end()){
L=lst[a[i]]+1;
}else{
L=1;
}
if(L<=i-1){
//比如3 1 2 4 3,最新加入的3,所以[1 2 4 3],[2 4 3],[4 3]都应该更新不同数的个数
//由于维护的是mx-mn-cnt,所以是-1
ac.update(1,1,n,L,i-1,-1);
}
lst[a[i]]=i;
//以当前a[i]为右端点元素的合法区间个数
//因为加入新节点(R,R)后,mn[1]肯定为-1,所以无需判断
ans+=1ll*ac.sm[1];
}
printf("Case #%d: %lld\n",cas,ans);
}
}

2018icpc宁夏邀请赛_L_Continuous Intervals的更多相关文章

  1. 2018宁夏邀请赛 Continuous Intervals(单调栈 线段树

    https://vjudge.net/problem/Gym-102222L 题意:给你n个数的序列,让判断有几个区间满足排完序后相邻两数差都不大于1. 题解:对于一个区间 [L,R],记最大值为 m ...

  2. 2018icpc宁夏邀请赛网络赛_G_Trouble of Tyrant

    题意 一列\(n\)个点,给定一个特殊的图,有两种边\(E(1,i)\)和\(E(i-1,i)\),多个询问,每次给一个\(d\),求所有路径长度加上\(d\)后1到\(n\)的最短路. 分析 首先这 ...

  3. 2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树)

    2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树) 传送门:https://nanti.jisuanke.com/t/41296 题意: 给一个数列A 问在数列A中有多 ...

  4. [ICPC 2018 宁夏邀请赛] A-Maximum Element In A Stack(思维)

    >传送门< 前言 辣鸡网络赛,虽然我是个菜鸡,然而好几个队伍十几分钟就AK???我心态那会彻底崩了,后来群里炸了,话题直接上知乎热搜,都是2018ICPC宁夏网络赛原题,这怎么玩,拼手速? ...

  5. 2018宁夏邀请赛L Continuous Intervals

    题目链接:https://nanti.jisuanke.com/t/28412 题意: 给出n个数的序列.问序列中有多少个区间满足,排序完之后任意两个相邻的数之差不大于1. 题解: 用max表示区间最 ...

  6. 2018宁夏邀请赛 L. Continuous Intervals

    转化一下询问即为区间$max - min + 1 = cnt$,其中$cnt$表示区间内数的种类数. 即求有多少区间$max - min - cnt=-1$,注意到任意区间的$max-min-cnt ...

  7. 2018acm-icpc宁夏邀请赛后记

    由于要准备期末考试的缘故,时隔一个月之后我才想起来还有一场比赛没有总结. 大概是出去过的最远的地方了,宁夏理工学院离杭州有两千多千米. 不得不说感到了主办方满满的诚意,虽然是第一次办比赛,但是第一天组 ...

  8. 2018宁夏邀请赛网赛 I. Reversion Count(java练习题)

    题目链接 :https://nanti.jisuanke.com/t/26217 Description: There is a positive integer X, X's reversion c ...

  9. “2018宁夏邀请赛 ” 兼 “The 2019 Asia Yinchuan First Round Online Programming”

    ------------7题弟弟,被各位半小时13题的大佬打惨了(滑稽)---------- 签到题就不写了. F :Moving On            (1247ms) 题意:给定大小为N的带 ...

随机推荐

  1. max函数结合lambda使用

    说明:d.keys() 以及列表可以看做lambda函数的实参,max的判断对象是key的值.最终返回的是使得key的值最大的那个实参.

  2. Postman(二)、调试模式

    postman提供了一个调试模式,很方便我们写脚本以及断言 在脚本中用console.log()打印,到控制台查看 比如写入如下脚本: 点击Send后,在控制台可以看到如下信息

  3. C++入门经典-例3.1-判断输入的数字是否为奇数

    1:代码如下: // 3.1.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using ...

  4. (转)mysql基础命令

    Sql代码 asc 按升序排列 desc 按降序排列 下列语句部分是Mssql语句,不可以在access中使用. SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE ...

  5. python3笔记二十三:正则表达式之其他函数

    一:学习内容 re.split函数 re.finditer函数 re.sub函数 group()分组 re.compile函数 二:字符串切割---re.split函数 需要导入包:import re ...

  6. 【Spark机器学习速成宝典】基础篇01Windows下spark开发环境搭建+sbt+idea(Scala版)

    注意: spark用2.1.1 scala用2.11.11 材料准备 spark安装包 JDK 8 IDEA开发工具 scala 2.11.8 (注:spark2.1.0环境于scala2.11环境开 ...

  7. spark MLlib 概念 5: 余弦相似度(Cosine similarity)

    概述: 余弦相似度 是对两个向量相似度的描述,表现为两个向量的夹角的余弦值.当方向相同时(调度为0),余弦值为1,标识强相关:当相互垂直时(在线性代数里,两个维度垂直意味着他们相互独立),余弦值为0, ...

  8. Python 抓取数据存储到Redis中

    redis是一个key-value存储结构.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set ...

  9. 三种CSS样式

    内联式css样式,直接写在现有的HTML标签中 CSS样式可以写在哪些地方呢?从CSS 样式代码插入的形式来看基本可以分为以下3种:内联式.嵌入式和外部式三种. 内联式css样式表就是把css代码直接 ...

  10. 1.2 Mac下配置maven环境变量

    1.下载JDK http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 2.下载Mave ...