【2019银川网络赛】L:Continuous Intervals
题目大意:给定一个长度为 N 的序列,定义连续区间 [l, r] 为:序列的一段子区间,满足 [l, r] 中的元素从小到大排序后,任意相邻两项的差值不超过1。求一共有多少个连续区间。
题解:单调栈 + 线段树
首先,对于区间计数类问题常规的思路是枚举区间的左端点或右端点,统计以该点为端点的区间个数,加入答案贡献。
对于这道题来说,不妨枚举答案的右端点 r,那么对于每个 r,需要快速得出有多少个左端点 l,使得区间 [l, r] 满足连续区间的性质。若能在 \(O(logn)\) 的时间内得出答案即可解决本题。
根据连续区间的性质,可知连续区间的定义等价于
\]
其中,cnt 为区间 [l, r] 中不同数字的个数。可以发现,只有取得等号的时候才满足连续区间的性质,即:\(max - min - cnt = -1\)。因此,对于每个枚举到的右端点 r,我们需要知道每个小于 r 的 l, [l, r] 区间的最大值和最小值以及区间不同数的个数。
可以利用线段树维护 \(max - min - cnt\),只需维护区间最小值以及区间最小值的个数,即可在线段树上快速回答询问。
维护区间最值可以利用单调栈,即:第 i 个元素入栈时,栈内元素由于单调性,自然维护了区间[i, r] 的最值,每次从栈中弹出元素时,需要在线段树上修改维护的最值贡献。
维护区间颜色数是一个经典问题,即:维护一个 pre 数组,用于记录上一次某个元素出现的位置。
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
struct node { // max - min - cnt >= -1
#define ls(o) t[o].lc
#define rs(o) t[o].rc
int lc, rc;
LL mi, cnt, add;
};
vector<node> t;
int tot, rt;
inline void up(int o) {
if (t[ls(o)].mi == t[rs(o)].mi) {
t[o].mi = t[ls(o)].mi;
t[o].cnt = t[ls(o)].cnt + t[rs(o)].cnt;
} else if (t[ls(o)].mi < t[rs(o)].mi) {
t[o].mi = t[ls(o)].mi;
t[o].cnt = t[ls(o)].cnt;
} else {
t[o].mi = t[rs(o)].mi;
t[o].cnt = t[rs(o)].cnt;
}
}
inline void down(int o) {
if (t[o].add != 0) {
t[ls(o)].mi += t[o].add, t[ls(o)].add += t[o].add;
t[rs(o)].mi += t[o].add, t[rs(o)].add += t[o].add;
t[o].add = 0;
}
}
inline int newnode() {
++tot;
t[tot].lc = t[tot].lc = t[tot].mi = t[tot].cnt = t[tot].add = 0;
return tot;
}
void build(int &o, int l, int r) {
o = newnode();
if (l == r) {
t[o].mi = t[o].add = 0, t[o].cnt = 1;
return;
}
int mid = l + r >> 1;
build(ls(o), l, mid);
build(rs(o), mid + 1, r);
up(o);
}
void modify(int o, int l, int r, int x, int y, LL add) {
if (l == x && r == y) {
t[o].mi += add, t[o].add += add;
return;
}
int mid = l + r >> 1;
down(o);
if (y <= mid) {
modify(ls(o), l, mid, x, y, add);
} else if (x > mid) {
modify(rs(o), mid + 1, r, x, y, add);
} else {
modify(ls(o), l, mid, x, mid, add);
modify(rs(o), mid + 1, r, mid + 1, y, add);
}
up(o);
}
int main() {
int T, kase = 0;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
t.resize(2 * n), tot = 0;
build(rt, 1, n);
vector<pair<int, int>> mi(n + 1), mx(n + 1);
int top1 = 0, top2 = 0;
map<int, int> pre;
LL ans = 0;
for (int i = 1, now; i <= n; i++) { // <val, pos>
now = i;
while (top1 > 0 && a[i] < mi[top1].first) {
int pos = mi[top1 - 1].second;
modify(rt, 1, n, pos + 1, now - 1, mi[top1].first - a[i]);
--top1;
now = pos + 1;
}
mi[++top1] = make_pair(a[i], i);
now = i;
while (top2 > 0 && a[i] > mx[top2].first) {
int pos = mx[top2 - 1].second;
modify(rt, 1, n, pos + 1, now - 1, a[i] - mx[top2].first);
--top2;
now = pos + 1;
}
mx[++top2] = make_pair(a[i], i);
if (pre.find(a[i]) != pre.end()) {
int pos = pre[a[i]];
modify(rt, 1, n, pos + 1, i, -1);
} else {
modify(rt, 1, n, 1, i, -1);
}
pre[a[i]] = i;
if (t[rt].mi == -1) {
ans += t[rt].cnt;
}
}
printf("Case #%d: %lld\n", ++kase, ans);
}
return 0;
}
【2019银川网络赛】L:Continuous Intervals的更多相关文章
- 2019南昌网络赛I:Yukino With Subinterval(CDQ) (树状数组套主席树)
题意:询问区间有多少个连续的段,而且这段的颜色在[L,R]才算贡献,每段贡献是1. 有单点修改和区间查询. 思路:46min交了第一发树套树,T了. 稍加优化多交几次就过了. 不难想到,除了L这个点, ...
- ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval
ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval 题目大意:给一个长度为n,值域为[1, n]的序列{a},要求支持m次操作: 单点修改 1 pos val 询 ...
- ICPC 2019 徐州网络赛
ICPC 2019 徐州网络赛 比赛时间:2019.9.7 比赛链接:The Preliminary Contest for ICPC Asia Xuzhou 2019 赛后的经验总结 // 比赛完才 ...
- 2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树)
2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树) 传送门:https://nanti.jisuanke.com/t/41296 题意: 给一个数列A 问在数列A中有多 ...
- ACM-ICPC 2019南昌网络赛F题 Megumi With String
ACM-ICPC 南昌网络赛F题 Megumi With String 题目描述 给一个长度为\(l\)的字符串\(S\),和关于\(x\)的\(k\)次多项式\(G[x]\).当一个字符串\(str ...
- 2019 南京网络赛A
南京网络赛自闭现场 https://nanti.jisuanke.com/t/41298 二维偏序经典题型 二维前缀和!!! #include<bits/stdc++.h> using n ...
- 2018ICPC银川 L Continuous Intervals 单调栈 线段树
题意:给你一个序列,问你这个序列有多少个子区间,满足把区间里的数排序之后相邻两个数之间的差 <= 1 ? 思路:https://blog.csdn.net/u013534123/article/ ...
- 2019 ICPC 银川网络赛 D. Take Your Seat (疯子坐飞机问题)
Duha decided to have a trip to Singapore by plane. The airplane had nn seats numbered from 11 to nn, ...
- 2019 ICPC 银川网络赛 H. Fight Against Monsters
It is my great honour to introduce myself to you here. My name is Aloysius Benjy Cobweb Dartagnan Eg ...
随机推荐
- 基于nodeJS的小说爬虫实战
背景与需求分析 最近迷恋于王者荣耀.斗鱼直播与B站吃播视频,中毒太深,下班之后无心看书. 为了摆脱现状,能习惯看书,我开始看小说了,然而小说网站广告多而烦,屌丝心态不愿充钱,于是想到了爬虫. 功能分析 ...
- Docker-Compose运行Nginx+Redis+NetCoreAPI
Docker-Compose运行Nginx+Redis+NetCoreAPI 一.准备Docker-Compose Docker 开始安装Docker-compose之前你需要先确认已经安装了Dock ...
- Unity* 实体组件系统 (ECS)、C# 作业系统和突发编译器入门
Unity* 中的全新 C# 作业系统和实体组件系统不仅可以让您轻松利用以前未使用的 CPU 资源,还可以帮助您更高效地运行所有游戏代码.然后,您可以使用这些额外的 CPU 资源来添加更多场景动态和沉 ...
- @Validated和@Valid校验参数、级联属性、List
@Validated和@Valid的区别 在Controller中校验方法参数时,使用@Valid和@Validated并无特殊差异(若不需要分组校验的话): @Valid:标准JSR-303规范的标 ...
- JS中FireFox新开窗口预览打印处理的方式
仅提供思路,勿喷如下↓ /** * 打印方法 * @param dom 要被打印的dom元素 * @param parentClassName 该组件的页面根组件class名 * @param pag ...
- Laravel 查询&数据库&模型
1.with()与load区别: 都称为 延迟预加载,不同点在于 load()是在已经查询出来的模型上调用,而 with() 则是在 ORM 查询构造器上调用. Order::query()-> ...
- windows下命令行利器---Cmder(安装,中文乱码,配置右键菜单)
很多人都是在win下开发的,这样就会出现,经常需要命令行操作,而win cmd命令和linux命令有很大差异,导致大家很难受,今天给大家介绍一个win下命令行的利器-Cmder 一.先看一下它的容颜 ...
- java限流工具类
代码 import com.google.common.util.concurrent.RateLimiter; import java.util.concurrent.ConcurrentHashM ...
- 用纯 CSS 创作一个在容器中反弹的小球
效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/jKVbyE 可交互视频教 ...
- 在Linux中,没有文件创建时间的概念。只有文件的访问时间、修改时间、状态改变时间
在Linux中,没有文件创建时间的概念.只有文件的访问时间.修改时间.状态改变时间.也就是说不能知道文件的创建时间.但如果文件创建后就没有修改过,修改时间=创建时间:如果文件创建后,状态就没有改变过, ...