【题解】【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;
}

浙公网安备 33010602011771号