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

传送门:https://nanti.jisuanke.com/t/41296

题意:

给一个数列A

问在数列A中有多少个区间满足,区间内数字排序后是一段连续的连续的区间

即排序后区间内的任意元素满足 \(a_{i+1}-a_i<=1\)

题解:

根据题意可知

满足题意的区间应当满足以下性质:

\(max-min==num-1\)

即当前区间最大的数字减去当前区间最小的数字等于区间数字的种类数

我们枚举区间的右端点\(R_i\),那么问题就转换为了有多少个\(L_j,j<=i\)

在区间\(L_j,R_i\)中,

\(Max-Min-num==-1\)

我们需要快速的得到所有满足上式\(L_j\)的个数

也就是 我们需要快速的得到区间 \([1,R_i]\)内满足上式的个数

我们可以用线段树来维护\(Max-Min-num\)这个值

查询就查询有多少个L对应这个值,如果\(Max-Min-num==-1\)

那么对应的值的个数可以对答案产生贡献

线段树维护\(Max-Min-num\)这个值时

我们可以用两个单调栈分别维护Max和Min的值,用map来维护区间数字出现的位置

对于每一次\(Max\)值的更新来说,我们需要减去当前的最大值a[i]-要删去的值的最大值staMax[tp]

对于每一次\(Min\)值的更新来说,我们需要减去要删去的值的最小值staMin[tp]-当前的最小值a[i]

对于每一次出现的数字,他的种类数可能会改变,我们需要在他上一次出现的位置到这个位置这个区间上-1

在查询的时候,我们只需要得到对应的\(Max-Min- num\)最小值为-1的个数即可

代码:

/**
*        ┏┓    ┏┓
*        ┏┛┗━━━━━━━┛┗━━━┓
*        ┃       ┃  
*        ┃   ━    ┃
*        ┃ >   < ┃
*        ┃       ┃
*        ┃... ⌒ ...  ┃
*        ┃       ┃
*        ┗━┓   ┏━┛
*          ┃   ┃ Code is far away from bug with the animal protecting          
*          ┃   ┃ 神兽保佑,代码无bug
*          ┃   ┃           
*          ┃   ┃       
*          ┃   ┃
*          ┃   ┃           
*          ┃   ┗━━━┓
*          ┃       ┣┓
*          ┃       ┏┛
*          ┗┓┓┏━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/
// warm heart, wagging tail,and a smile just for you!
//
// _ooOoo_
// o8888888o
// 88" . "88
// (| -_- |)
// O\ = /O
// ____/`---'\____
// .' \| |// `.
// / \||| : |||// \
// / _||||| -:- |||||- \
// | | \ - /// | |
// | \_| ''\---/'' | |
// \ .-\__ `-` ___/-. /
// ___`. .' /--.--\ `. . __
// ."" '< `.___\_<|>_/___.' >'"".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `-. \_ __\ /__ _/ .-` / /
// ======`-.____`-.___\_____/___.-`____.-'======
// `=---='
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// 佛祖保佑 永无BUG
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
double ans = 1.0;
while(b) {
if(b % 2)ans = ans * a;
a = a * a;
b /= 2;
} return ans;
}
LL quick_pow(LL x, LL y) {
LL ans = 1;
while(y) {
if(y & 1) {
ans = ans * x % mod;
} x = x * x % mod;
y >>= 1;
} return ans;
}
/*
给你长为 1e5的数组,
要你求其中有多少个区间使得这个区间中的值域是个连续的区间,
即排序后两两个值的差小于等于1。
*/ int Min[maxn << 2];
int num[maxn << 2];
int lazy[maxn << 2];
void push_up(int rt) {
Min[rt] = min(Min[ls], Min[rs]);
if(Min[ls] == Min[rs]) {
num[rt] = num[ls] + num[rs];
} else if(Min[rt] == Min[ls]) {
num[rt] = num[ls];
} else {
num[rt] = num[rs];
}
}
void build(int l, int r, int rt) {
Min[rt] = 0;
lazy[rt] = 0;
num[rt] = r - l + 1;
if(l == r) {
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
// push_up(rt);
}
void push_down(int rt) {
if(lazy[rt]) {
lazy[ls] += lazy[rt];
lazy[rs] += lazy[rt];
Min[ls] += lazy[rt];
Min[rs] += lazy[rt];
lazy[rt] = 0;
}
}
void update(int L, int R, int val, int l, int r, int rt) {
if(L <= l && r <= R) {
Min[rt] += val;
lazy[rt] += val;
return;
}
push_down(rt);
int mid = (l + r) >> 1;
if(L <= mid) update(L, R, val, lson);
if(R > mid) update(L, R, val, rson);
push_up(rt);
}
pii query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
return make_pair(Min[rt], num[rt]);
}
push_down(rt);
int mid = (l + r) >> 1;
pii tmp1 = make_pair(INF, 0), tmp2 = make_pair(INF, 0);
if(L <= mid) {
tmp1 = query(L, R, lson);
}
if(R > mid) {
tmp2 = query(L, R, rson);
}
pii ans;
if(tmp1.first == tmp2.first) {
ans = make_pair(tmp1.first, tmp1.second + tmp2.second);
return ans;
}
if(tmp1.first < tmp2.first) {
ans = tmp1;
return ans;
} else {
ans = tmp2;
return ans;
}
return ans;
}
int a[maxn];
pii Maxsta[maxn], Minsta[maxn];
map<int, int>mp;
int main() {
#ifndef ONLINE_JUDGE
FIN
#endif
int T;
scanf("%d", &T);
int cas = 1;
while(T--) {
int n;
int tpMax = 0;
int tpMin = 0;
scanf("%d", &n);
build(1, n, 1);
mp.clear();
LL ans = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= n; i++) {
// mp[a[i]] = i;
while(tpMax > 0 && Maxsta[tpMax].first < a[i]) {
//减去小于当前值的Max贡献
update(Maxsta[tpMax - 1].second + 1, Maxsta[tpMax].second, a[i] - Maxsta[tpMax].first, 1, n, 1);
tpMax--;
}
Maxsta[++tpMax] = make_pair(a[i], i); while(tpMin > 0 && Minsta[tpMin].first > a[i]) {
//减去大于当前值的Min贡献
update(Minsta[tpMin - 1].second + 1, Minsta[tpMin].second, Minsta[tpMin].first - a[i], 1, n, 1);
tpMin--;
}
Minsta[++tpMin] = make_pair(a[i], i);
//减去重复数字的贡献
update(mp[a[i]] + 1, i, -1, 1, n, 1);
mp[a[i]] = i;
pii flag = query(1, i, 1, n, 1);
if(flag.first == -1) {
ans += flag.second;
}
}
printf("Case #%d: %lld\n", cas++, ans); }
return 0;
}

2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树)的更多相关文章

  1. 2018ICPC银川 L Continuous Intervals 单调栈 线段树

    题意:给你一个序列,问你这个序列有多少个子区间,满足把区间里的数排序之后相邻两个数之间的差 <= 1 ? 思路:https://blog.csdn.net/u013534123/article/ ...

  2. 2018宁夏邀请赛L Continuous Intervals

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

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

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

  4. 南昌邀请赛I.Max answer 单调栈+线段树

    题目链接:https://nanti.jisuanke.com/t/38228 Alice has a magic array. She suggests that the value of a in ...

  5. 洛谷P4198 楼房重建 单调栈+线段树

    正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...

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

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

  7. 2019ICPC南昌邀请赛网络赛 I. Max answer (单调栈+线段树/笛卡尔树)

    题目链接 题意:求一个序列的最大的(区间最小值*区间和) 线段树做法:用单调栈求出每个数两边比它大的左右边界,然后用线段树求出每段区间的和sum.最小前缀lsum.最小后缀rsum,枚举每个数a[i] ...

  8. The Preliminary Contest for ICPC China Nanchang National Invitational I. Max answer (单调栈+线段树)

    题目链接:https://nanti.jisuanke.com/t/38228 题目大意:一个区间的值等于该区间的和乘以区间的最小值.给出一个含有n个数的序列(序列的值有正有负),找到该序列的区间最大 ...

  9. 2019南昌网络赛-I(单调栈+线段树)

    题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上 ...

随机推荐

  1. 【Leetcode栈】有效的括号(20)

    题目 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 1,左括号必须用相同类型的右括号闭合. 2,左括号必须以正确的顺序闭合. 注意 ...

  2. Effective C++: 05实现

    26:尽可能延后变量定义式的出现时间 1:只要你定义了一个变量而其类型带有一个构造函数或析构函数,那么当程序的控制流到达这个变量定义式时,你便得承受构造成本:当这个变量离开其作用域时,你便得承受析构成 ...

  3. 《C程序设计语言》笔记(二)

    四:函数与程序结构 1:函数之间的通信可以通过参数.函数返回值以及外部变量进行. 2:如果函数定义中省略了返回值类型,则默认为int类型.如果没有函数原型,则函数将在第一次出现的表达式中被隐式声明,比 ...

  4. 在window.onload中使用setTimeout

    window.onload = function(){ function n(i){ alert(1); } setTimeout('n(1)',2000); } 以上代码会报错:n() is not ...

  5. du,df区别

    1.记住命令 du:disk Usage -h, --human-readable print sizes in human readable format df:disk free 2.区别 du ...

  6. P2P需集齐四大证照

    今后做P2P需集齐四大证照 比牌照制还严 2016-09-05 11:53:24 分类:热点观察 作者:汪祖刚 8月24日,P2P网贷监管细则在千呼万唤中始出来,整个行业内外的关注热度可谓史无前例.有 ...

  7. LeetCode81 Search in Rotated Sorted Array II

    题目: Follow up for "Search in Rotated Sorted Array":What if duplicates are allowed? Would t ...

  8. [***]HZOJ 超级树

    DeepinC超详细题解 考试时想出是dp了,因为显然第i级超级树和第i+1级超级树是有联系的(然而我并不能推出来),这dp的状态鬼才想的出来……个人理解,dp的实质就是从小的状态向大的状态转移,从而 ...

  9. U盘还原系统

    相信现在不少的人已经开始使用U盘作为启动盘来安装系统,说起来这可比用光盘装系统可是方便多了.毕竟U盘可以随身携带,至于光盘嘛,就不多说了.       可是还有许多人对U盘安装系统还是有些陌生的感觉. ...

  10. lodap问题集锦

    1.分页打印时,同一行显示在不同页内 ,调整行分页粒度 LODOP.SET_PRINT_STYLEA(0, "TableRowThickNess", 40);