题意:
个数的一个序列,对于一个连续区间,将这个区间内的数排序,相邻数字差距小于等于 ,则这个区间符合条件。问这个序列中有多少个符合条件的连续区间。
思路:
这是一个区间计数问题,即询问一个序列中符合条件的区间个数。通常此类问题的思考方向是确定一个左端点,求有多少个符合条件的右端点。或者确定一个右端点,求有多少个符合条件的左端点。
然后我们再思考,如何判断一个区间符合条件。区间符合条件的要求即为 , 为区间中最大的数, 为区间中最小的数, 为区间中不同大小的数的个数。
然后我们枚举右端点 ,查询有多少个 ,使得区间 符合条件。然后线段树中对于每一个位置 ,维护 中 的值。对于 和 ,我们可以用单调栈来进行更新,边维护单调栈边更新线段树中每个点的值。对于 ,我们用 记录每一个数字上一次出现的位置,然后更新需要更新的区间。
至此我们就只需要维护每一个区间的最小值,以及最小值的个数,可以发现最小值一定大于等于 ,因此对于每个 统计答案即可。
代码:
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a);
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define per(i,a,b) for(int i = a; i >= b; i--)
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
typedef long long ll;
typedef double db;
const int N = 1e5+100;
const db EPS = 1e-9;
using namespace std;
void dbg() {cout << "\n";}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}
int n,t1,t2;
ll a[N],ans,minn[2*N],num[2*N],lazy[2*N]; //最小值,最小值个数
pair<ll,int> st1[N],st2[N];
map<ll,int> mp;
inline int get_id(int l,int r) {return (l+r) | (l!=r);}
void push_down(int l,int r){
int now = get_id(l,r), mid = (l+r)>>1;
int ls = get_id(l,mid), rs = get_id(mid+1,r);
minn[ls] += lazy[now]; minn[rs] += lazy[now];
lazy[ls] += lazy[now]; lazy[rs] += lazy[now];
lazy[now] = 0;
}
void push_up(int l,int r){
int now = get_id(l,r), mid = (l+r)>>1;
int ls = get_id(l,mid), rs = get_id(mid+1,r);
if(minn[ls] == minn[rs]) minn[now] = minn[ls], num[now] = num[ls]+num[rs];
else if(minn[ls] < minn[rs]) minn[now] = minn[ls], num[now] = num[ls];
else minn[now] = minn[rs], num[now] = num[rs];
}
void build(int l,int r){
int now = get_id(l,r);
minn[now] = 0, num[now] = r-l+1, lazy[now] = 0;
if(l == r) return;
int mid = (l+r)>>1;
build(l,mid); build(mid+1,r);
}
void update(int l,int r,int p1,int p2,ll c){ //区间修改
int now = get_id(l,r);
if(p1 <= l && r <= p2){
minn[now] += c; lazy[now] += c;
return;
}
if(lazy[now] != 0) push_down(l,r);
int mid = (l+r)>>1;
if(p1 <= mid) update(l,mid,p1,p2,c);
if(p2 > mid) update(mid+1,r,p1,p2,c);
push_up(l,r);
}
void init(){
ans = t1 = t2 = 0;
build(1,n); mp.clear();
}
int main()
{
int _; scanf("%d",&_);
rep(Ca,1,_){
scanf("%d",&n);
rep(i,1,n) scanf("%lld",&a[i]);
init();
rep(i,1,n){
//处理最大值 —— st1
int now = i;
while(t1 > 0 && st1[t1].first < a[i]){
int pos = st1[t1-1].second;
update(1,n,pos+1,now-1,-st1[t1].first+a[i]);
t1--; now = pos+1;
}
st1[++t1] = make_pair(a[i],i);
//处理最小值 —— st2
now = i;
while(t2 > 0 && st2[t2].first > a[i]){
int pos = st2[t2-1].second;
update(1,n,pos+1,now-1,st2[t2].first-a[i]);
// logs(pos,now-1,st2[t2].first-a[i]);
t2--; now = pos+1;
}
st2[++t2] = make_pair(a[i],i);
//处理cnt
if(mp.find(a[i]) != mp.end()){
int pos = mp[a[i]];
update(1,n,pos+1,i,-1);
}
else update(1,n,1,i,-1);
mp[a[i]] = i;
//计算答案
if(minn[get_id(1,n)] == -1) ans += num[get_id(1,n)];
}
printf("Case #%d: %lld\n",Ca,ans);
}
return 0;
}