怎么还有这么套路的题?
考虑按
r
i
r_i
ri排序,问题就变为求出有多少个区间满足
c
i
c_i
ci为连续段。这个问题有经典的线段树+单调栈做法。
具体来说,我们考虑对右端点
r
r
r做扫描线,计算有多少个合法的左端点
l
l
l,那么合法条件是
max
i
=
l
r
c
i
−
min
i
=
l
r
c
i
=
r
−
l
\max_{i=l}^{r}c_i-\min_{i=l}^{r}c_i=r-l
maxi=lrci−mini=lrci=r−l,注意到左边一定不小于右边,因此作差后只需查询区间最小值个数即可。用一个支持区间加和查询区间最小值数目的线段树即可。
至于
max
\max
max和
min
\min
min的话,用单调栈维护连续的区间即可。均摊时间复杂度
O
(
n
log
n
)
\mathcal O(n\log n)
O(nlogn)。
#include <bits/stdc++.h>
#define FR first
#define SE second
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline pr merge(pr x,pr y) {
if (x.FR!=y.FR) return (x.FR<y.FR)?x:y;
return pr(x.FR,x.SE+y.SE);
}
namespace SGT {
pr minn[1200000];
int addv[1200000];
inline void pushdown(int o) {
if (addv[o]) {
addv[o*2]+=addv[o];
minn[o*2].FR+=addv[o];
addv[o*2+1]+=addv[o];
minn[o*2+1].FR+=addv[o];
addv[o]=0;
}
}
inline void pushup(int o) {
minn[o]=merge(minn[o*2],minn[o*2+1]);
}
void build(int l,int r,int o) {
if (l==r) minn[o]=pr(0,1);
else {
int m=((l+r)>>1);
build(l,m,o*2);
build(m+1,r,o*2+1);
pushup(o);
}
}
void update(int l,int r,int o,int lx,int rx,int p) {
if (l>=lx&&r<=rx) {
addv[o]+=p;
minn[o].FR+=p;
}
else {
pushdown(o);
int m=((l+r)>>1);
if (m>=lx) update(l,m,o*2,lx,rx,p);
if (m<rx) update(m+1,r,o*2+1,lx,rx,p);
pushup(o);
}
}
pr query(int l,int r,int o,int lx,int rx) {
if (l>=lx&&r<=rx) return minn[o];
else {
pushdown(o);
int m=((l+r)>>1);
if (m>=rx) return query(l,m,o*2,lx,rx);
if (m<lx) return query(m+1,r,o*2+1,lx,rx);
return merge(query(l,m,o*2,lx,rx),query(m+1,r,o*2+1,lx,rx));
}
}
}
int num[300005];
int st1[300005],st2[300005];
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
int x,y;
scanf("%d%d",&x,&y);
num[x]=y;
}
SGT::build(1,n,1);
ll ans=0;
int top1=0,top2=0;
for(int i=1;i<=n;i++) {
while (top1&&num[st1[top1]]<num[i]) {
SGT::update(1,n,1,st1[top1-1]+1,st1[top1],num[i]-num[st1[top1]]);
top1--;
}
st1[++top1]=i;
while (top2&&num[st2[top2]]>num[i]) {
SGT::update(1,n,1,st2[top2-1]+1,st2[top2],num[st2[top2]]-num[i]);
top2--;
}
st2[++top2]=i;
if (i>1) SGT::update(1,n,1,1,i-1,-1);
ans+=SGT::query(1,n,1,1,i).SE;
}
printf("%lld\n",ans);
return 0;
}