【题解】【Pudding Monsters】

我们先把输入的点映射到一个排列,设\(w(i,j)=[max(a_i,a_{i+1},\cdots ,a_j)-min(a_i,a_{i+1},\cdots ,a_j)=j-i]\),题目所求即为\(\sum_{j=1}^n\sum_{i=1}^jw(i,j)\)

我们可以考虑扫描一维,比如右端点\(j\),同时用数据结构对每个小于\(j\)\(i\)维护出\(w(i,j)\),
这里有个巧妙的转化,注意到\(max(a_i,a_{i+1},\cdots ,a_j)-min(a_i,a_{i+1},\cdots ,a_j)\geq j-i\),
移项得,\(max(a_i,a_{i+1},\cdots ,a_j)-min(a_i,a_{i+1},\cdots ,a_j)+i\geq j\)
也就是说我们维护不等式左边的话,只需维护最小值和最小值个数,如果最小值恰为j的话,答案就加上最小值个数

继续观察\(max(a_i,a_{i+1},\cdots ,a_j)-min(a_i,a_{i+1},\cdots ,a_j)+i\),
\(i\)好处理,但是后缀\(max\)和后缀\(min\)如果采用区间赋值或区间\(chkmin\)这样的操作是很难维护整个式子的,但是如果是区间加的话,就可以将\(max\)\(min\)分开做了,于是我们考虑用区间加来维护。

以最大值为例,用一个单调栈维护\([1,j]\)中所有的点的后缀\(max\),那么这个栈显然是单调递减的,每个点对应一个区间,每次弹掉栈顶小于当前点的元素,同时在线段树上把对应的区间进行修改,最后把当前点入栈。最小值同理。

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define db long double

int rd()
{
	int x=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)&&ch!='-') ch=getchar();
	if(ch=='-') ch=getchar(),w=-1;
	while(isdigit(ch)) x=x*10+(ch-48),ch=getchar();
	return x*w;
}
const int N=3e5+100;
int n,a[N],mx[N],mn[N],t1,t2;
struct node{
	int l,r,minn,sum,tag;
}t[N<<2];
void build(int x,int l,int r)
{
	t[x].l=l,t[x].r=r;
	t[x].minn=l;
	t[x].sum=1;
	if(l==r) return;
	int mid=l+r>>1;
	build(x<<1,l,mid);build(x<<1|1,mid+1,r);
}
void pushdown(int x)
{
	int d=t[x].tag;t[x].tag=0;
	if(d==0) return;
	t[x<<1].minn+=d;t[x<<1].tag+=d;
	t[x<<1|1].minn+=d;t[x<<1|1].tag+=d;
}
void pushup(int x)
{
	if(t[x<<1].minn==t[x<<1|1].minn) {
		t[x].minn=t[x<<1].minn;
		t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
	}
	else {
		t[x].minn=min(t[x<<1].minn,t[x<<1|1].minn);
		t[x].sum=(t[x<<1].minn==t[x].minn?t[x<<1].sum:t[x<<1|1].sum);
	}
}
void change(int x,int l,int r,int val)
{
	if(t[x].l>=l&&t[x].r<=r)
	{
		t[x].minn+=val;t[x].tag+=val;return;
	}
	pushdown(x);
	int mid=t[x].l+t[x].r>>1;
	if(l<=mid) change(x<<1,l,r,val);
	if(r>mid) change(x<<1|1,l,r,val);
	pushup(x);
}
int query(int x,int pos,int r)
{
	if(t[x].r<=pos)
	{
		if(t[x].minn==r) return t[x].sum;
		return 0; 
	}
	pushdown(x);
	int mid=t[x].l+t[x].r>>1;
	if(pos<=mid) return query(x<<1,pos,r);
	return query(x<<1,pos,r)+query(x<<1|1,pos,r);
}
signed main()
{
    n=rd();
    for(int i=1;i<=n;++i) {
    	int x=rd(),y=rd();
    	a[x]=y;
	}
	build(1,1,n);
	int ans=0;mx[++t1]=0;mn[++t2]=0;
	for(int i=1;i<=n;++i)
	{
		while(t1-1&&a[mx[t1]]<a[i]) 
		change(1,mx[t1-1]+1,mx[t1],a[i]-a[mx[t1]]),t1--;
		while(t2-1&&a[mn[t2]]>a[i]) 
		change(1,mn[t2-1]+1,mn[t2],a[mn[t2]]-a[i]),t2--;
		mx[++t1]=i;mn[++t2]=i;
		ans+=query(1,i,i);
	}
	cout<<ans;
	return 0;
}

posted @ 2022-08-21 16:38  glq_C  阅读(29)  评论(0)    收藏  举报