[题目链接](E. Special Segments of Permutation)
题目思路
其实就是树上启发式合并的思维
单调栈预处理以\(a[i]\)为最大值的区间,然后每次只计算小区间
玄学一点分析,就是树上启发式合并
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n;
int a[maxn],l[maxn],r[maxn];
int pos[maxn];
stack<int> sta;
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
pos[a[i]]=i;
}
for(int i=n;i>=1;i--){
while(!sta.empty()&&a[sta.top()]<=a[i]){
sta.pop();
}
r[i]=sta.empty()?n:sta.top()-1;
sta.push(i);
}
while(!sta.empty()) sta.pop();
for(int i=1;i<=n;i++){
while(!sta.empty()&&a[sta.top()]<=a[i]){
sta.pop();
}
l[i]=sta.empty()?1:sta.top()+1;
sta.push(i);
}
int ans=0;
for(int i=1;i<=n;i++){
if(i-l[i]<r[i]-i){
for(int j=l[i];j<i;j++){
int other=pos[a[i]-a[j]];
if(other>i&&other<=r[i]){
ans++;
}
}
}else{
for(int j=i+1;j<=r[i];j++){
int other=pos[a[i]-a[j]];
if(other<i&&other>=l[i]){
ans++;
}
}
}
}
printf("%d\n",ans);
return 0;
}