「NOIP模擬」奇襲【線段樹】【單調棧】
阿新 • • 發佈:2018-11-05
題意:
給定數列,求有多少個區間滿足區間最大+1-區間最小=區間長度
滿足條件為:
所以我們考慮列舉 ,線段樹維護 的值,並且求出區間最小值與最小值個數。
在列舉 的過程中,當前區間再加上 後的新區間的
而 的變化也是一段區間同時變化,所以我們用類似分治做法維護兩個單調棧,一個單調遞增,一個單調遞減。
由於改變是區間同時變化,所以根據單調棧的值來對線段樹進行區間修改。
由於使用了單調棧,所以根據時間複雜度計算原理,均攤得:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#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<r) {
ll mid=l+r>>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]<a[up[cup-1]]) {
modify(1,1,n,up[cup-2]+1,up[cup-1],a[up[cup-1]]);
cup--;
}
while(cdown>=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;
}