CF526F Pudding Monsters
鸽了好久的题。
考虑先拍扁到一个序列上。
那么就是询问有多少个区间满足\(max - min = r - l\)
考虑无法直接统计。
我们考虑对每个\(r\)来统计。
在\(r\)向右扩展的同时要维护的值\(max,min,l,r\)
考虑到\(r - l \leq max - min\)
那么如果我们不考虑常量\(l\),则我们只需要维护区间最小值的数量。
那么向右扩展\(r\)的改变就是全局\(-1\),\(max,min\)是很经典的做法:单调栈维护位置,类似于\(FJD1T3\)
#include<iostream>
#include<cstdio>
#define ll long long
#define N 300005
ll sx[N],sn[N],stx,stn;
ll n;
ll a[N];
struct P{ll cnt,v,tag;}e[N << 2];
#define l(x) (x << 1)
#define r(x) (x << 1 | 1)
#define mid ((l + r) >> 1)
//mx - mi - (r - l) = 0
inline void build(ll u,ll l,ll r){
e[u].cnt = r - l + 1;
e[u].tag = 0;
if(l == r)
return ;
build(l(u),l,mid);
build(r(u),mid + 1,r);
}
ll ans;
inline void upd(ll u,ll l,ll r,ll tl,ll tr,ll p){
// std::cout<<u<<" "<<tl<<" "<<tr<<" "<<p<<" "<<std::endl;
if(tl <= l && r <= tr){
e[u].v += p;
e[u].tag += p;
return ;
}
if(e[u].tag){
e[l(u)].v += e[u].tag;
e[l(u)].tag += e[u].tag;
e[r(u)].v += e[u].tag;
e[r(u)].tag += e[u].tag;
e[u].tag = 0;
}
if(tl <= mid)
upd(l(u),l,mid,tl,tr,p);
if(tr > mid)
upd(r(u),mid + 1,r,tl,tr,p);
e[u].v = std::min(e[r(u)].v,e[l(u)].v);
e[u].cnt = (e[l(u)].v == e[u].v ? e[l(u)].cnt : 0) + (e[r(u)].v == e[u].v ? e[r(u)].cnt : 0);
}
int main(){
scanf("%lld",&n);
for(int i = 1;i <= n;++i){
ll x,y;
scanf("%lld%lld",&x,&y);
a[x] = y;
}
build(1,1,n);
for(int i = 1;i <= n;++i){
while(stx && a[sx[stx]] < a[i])upd(1,1,n,sx[stx - 1] + 1,sx[stx],-a[sx[stx]]),--stx;
while(stn && a[sn[stn]] > a[i])upd(1,1,n,sn[stn - 1] + 1,sn[stn],a[sn[stn]]),--stn;
upd(1,1,n,1,i,-1),sx[++stx] = sn[++stn] = i;
upd(1,1,n,sx[stx - 1] + 1,i,a[i]),upd(1,1,n,sn[stn - 1] + 1,i,-a[i]);
ans += e[1].cnt;
}
std::cout<<ans<<std::endl;
}