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("*********
")
#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)<<"]
"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]
"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]
"
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
", cas++, ans);
}
return 0;
}