騷區間
這種貢獻題可以發現,固定一個右邊界 i ,然後在 1–i-1 找出所有符合條件的左邊界 j ;
所以可以預處理出在 (1–i-1) 中大於 a[i] 的第一個元素位置p1,和第二個元素位置p2, 那麼(p2+1,p1)就是可以成爲 i 的左邊界,同樣可以處理右邊界;這裏可以運用權值線段樹,查找最大最小座標;
最後可以運用差分原理,統計答案;
代碼:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=1000100;
const int M=2000100;
const LL mod=1e9+7;
int a[N],n,l1[N],r1[N],l2[N],r2[N];
vector<pa>ve[N];
struct Node{
int l,r,mx,mi;
LL w;
}tr[N*4];
void pp(int k){
tr[k].mx=max(tr[ls].mx,tr[rs].mx);
tr[k].mi=min(tr[ls].mi,tr[rs].mi);
tr[k].w=tr[ls].w+tr[rs].w;
}
void build(int l,int r,int k){
tr[k].l=l,tr[k].r=r;
if(l==r){
tr[k].mx=0,tr[k].mi=2e9,tr[k].w=0;
return;
}
int d=(l+r)>>1;
build(l,d,ls);
build(d+1,r,rs);
pp(k);
}
void update_pos1(int pos,int w,int k){
if(tr[k].l==tr[k].r){
tr[k].mx=w;
return;
}
int d=(tr[k].l+tr[k].r)>>1;
if(pos<=d) update_pos1(pos,w,ls);
else update_pos1(pos,w,rs);
pp(k);
}
int query_pos1(int l,int r,int k){
if(l>r) return 0;
if(tr[k].l>=l&&tr[k].r<=r) return tr[k].mx;
int d=(tr[k].l+tr[k].r)>>1;
if(r<=d) return query_pos1(l,r,ls);
if(l>d) return query_pos1(l,r,rs);
return max(query_pos1(l,r,ls),query_pos1(l,r,rs));
}
void update_pos2(int pos,int w,int k){
if(tr[k].l==tr[k].r){
tr[k].mi=w;
return;
}
int d=(tr[k].l+tr[k].r)>>1;
if(pos<=d) update_pos2(pos,w,ls);
else update_pos2(pos,w,rs);
pp(k);
}
int query_pos2(int l,int r,int k){
if(l>r) return 2e9;
if(tr[k].l>=l&&tr[k].r<=r) return tr[k].mi;
int d=(tr[k].l+tr[k].r)>>1;
int ans=2e9;
if(r<=d) return query_pos2(l,r,ls);
if(l>d) return query_pos2(l,r,rs);
return min(query_pos2(l,r,ls),query_pos2(l,r,rs));
}
void update(int pos,int w,int k){
if(tr[k].l==tr[k].r){
tr[k].w+=(LL)w;
return;
}
int d=(tr[k].l+tr[k].r)>>1;
if(pos<=d) update(pos,w,ls);
else update(pos,w,rs);
pp(k);
}
LL query(int l,int r,int k){
if(l>r) return 0;
if(tr[k].l>=l&&tr[k].r<=r) return tr[k].w;
LL ans=0;
int d=(tr[k].l+tr[k].r)>>1;
if(l<=d) ans+=query(l,r,ls);
if(r>d) ans+=query(l,r,rs);
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,n,1);
for(int i=1;i<=n;i++){
int pos1=query_pos1(a[i]+1,n,1);//查找大於a[i]的元素最大下標
if(pos1){
r1[i]=pos1;
l1[i]=query_pos1(a[i]+1,a[pos1]-1,1)+1;
l1[i]=max(l1[i],query_pos1(a[pos1]+1,n,1)+1);
}
update_pos1(a[i],i,1);
}
build(1,n,1);
for(int i=n;i>=1;i--){
int pos2=query_pos2(1,a[i]-1,1);//查找小於a[i]的元素最小下標
if(pos2!=2e9){
l2[i]=pos2;
r2[i]=query_pos2(1,a[pos2]-1,1)-1;
r2[i]=min(r2[i],query_pos2(a[pos2]+1,a[i]-1,1)-1);
if(r2[i]>n) r2[i]=n;
}
update_pos2(a[i],i,1);
}
for(int i=1;i<=n;i++){
if(l2[i]&&r2[i]){
ve[l2[i]].push_back(pa(i,1));
ve[r2[i]+1].push_back(pa(i,-1));
}
}
LL ans=0;
for(int i=1;i<=n;i++){
for(int j=0;j<ve[i].size();j++) update(ve[i][j].first,ve[i][j].second,1);
if(l1[i]&&r1[i]) ans+=query(l1[i],r1[i],1);
}
printf("%lld\n",ans);
return 0;
}