题意:
给定数列,求有多少个区间满足区间最大+1-区间最小=区间长度
满足条件为:
m a x + 1 − m i n = r + 1 − l = > m a x − m i n = r − l max+1-min=r+1-l=>max-min=r-l max+1−min=r+1−l=>max−min=r−l
m a x − m i n + l = r max-min+l=r max−min+l=r
所以我们考虑枚举 r r r,线段树维护 m a x − m i n + l max-min+l max−min+l的值,并且求出区间最小值与最小值个数。
在枚举 r r r的过程中,当前区间再加上 r r r后的新区间的 n e w m a x ≥ m a x , n e w m i n ≤ m i n newmax\geq max,newmin\leq min newmax≥max,newmin≤min
而 n e w m a x , n e w m i n newmax,newmin newmax,newmin的变化也是一段区间同时变化,所以我们用类似分治做法维护两个单调栈,一个单调递增,一个单调递减。
由于改变是区间同时变化,所以根据单调栈的值来对线段树进行区间修改。
由于使用了单调栈,所以根据时间复杂度计算原理,均摊得: O ( n l o g n ) O(nlog_n) O(nlogn)
#include
#include
#include
#include
#include
#define db double
#define sg string
#define ll long long
#define rel(i,x,y) for(ll i=(x);i<(y);i++)
#define rep(i,x,y) for(ll i=(x);i<=(y);i++)
#define red(i,x,y) for(ll i=(x);i>=(y);i--)
#define res(i,x) for(ll i=head[x];i;i=nxt[i])
using namespace std;
const ll N=5e4+5;
const ll Inf=1e18;
const ll Mod=1e9+7;
const db Eps=1e-10;
ll n,m,ans,a[N],up[N<<2],down[N<<2],mn[N<<2],cnt[N<<2],lazy[N<<2];
#define lson (p<<1)
#define rson (p<<1|1)
inline ll read() {
ll x=0;char ch=getchar();bool f=0;
while(ch>'9'||ch<'0'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?-x:x;
}
void maketree(ll p,ll l,ll r) {
mn[p]=l;cnt[p]=1;
if(l>1;
maketree(lson,l,mid);
maketree(rson,mid+1,r);
}
}
void pushdown(ll p) {
if(lazy[p]) {
lazy[lson]+=lazy[p];
lazy[rson]+=lazy[p];lazy[p]=0;
}
}
void update(ll p) {
ll a=mn[lson]+lazy[lson];
ll b=mn[rson]+lazy[rson];
mn[p]=min(a,b);
cnt[p]=(a==mn[p]?cnt[lson]:0)+(b==mn[p]?cnt[rson]:0);
}
void modify(ll p,ll l,ll r,ll x,ll y,ll z) {
if(x<=l&&r<=y) {
lazy[p]+=z;return ;
}
pushdown(p);
ll mid=l+r>>1;
if(x<=mid) modify(lson,l,mid,x,y,z);
if(y>mid) modify(rson,mid+1,r,x,y,z);update(p);
}
void File() {
freopen("raid.in","r",stdin);
freopen("raid.out","w",stdout);
}
int main() {
File();
n=read();
memset(a,-1,sizeof(a));
rep(i,1,n) {
ll x=read(),y=read();a[x]=y;
}
maketree(1,1,n);
ll cup=1,cdown=1;up[0]=-1;down[0]=-1;
rep(i,1,n) {
while(cup>=2&&a[i]=2&&a[i]>a[down[cdown-1]]) {
modify(1,1,n,down[cdown-2]+1,down[cdown-1],-a[down[cdown-1]]);
cdown--;
}
up[cup++]=i;down[cdown++]=i;
modify(1,1,n,up[cup-2]+1,up[cup-1],-a[up[cup-1]]);
modify(1,1,n,down[cdown-2]+1,down[cdown-1],a[down[cdown-1]]);ans+=cnt[1];
}
printf("%lld\n",ans);
return 0;
}