CF526F Pudding Monsters

鸽了好久的题。
考虑先拍扁到一个序列上。
那么就是询问有多少个区间满足\(max - min = r - l\)
考虑无法直接统计。
我们考虑对每个\(r\)来统计。
\(r\)向右扩展的同时要维护的值\(max,min,l,r\)
考虑到\(r - l \leq max - min\)
那么如果我们不考虑常量\(l\),则我们只需要维护区间最小值的数量。
那么向右扩展\(r\)的改变就是全局\(-1\),\(max,min\)是很经典的做法:单调栈维护位置,类似于\(FJD1T3\)

CF526F Pudding Monsters
#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;
}
posted @ 2021-06-28 12:10  fhq_treap  阅读(36)  评论(0编辑  收藏  举报