显然先用单调栈求出一个位置向左/右延申的最大长度(即这些区间中当前位置是最大值位置)
然后我们发现我们可以离线,然后按照最大值位置依次添加线段,每次用线段树查一个区间和.
然后我们想查满足最大值位置在 $[l,r]$ 之间,$[l,r]$ 内区间和.
这个显然满足可减性(即最大值位置在 $[1,r]$ 减最大值位置在 $[1,l-1]$)
code:
#include <cstring>
#include <algorithm>
#include <string>
#include <stack>
#define N 1000006
#define lson now<<1
#define rson now<<1|1
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,Q;
int A[N],lp[N],rp[N];
stack<int>S;
ll sum[N<<2],lazy[N<<2],ans[N];
struct seq
{
int l,r,mid;
seq(int l=0,int r=0,int mid=0):l(l),r(r),mid(mid){}
}s[N];
struct ask {
int mid,l,r,id,opt;
}as[N<<1];
bool cmp(ask a,ask b) { return a.mid<b.mid; }
void update(int l,int r,int now,int L,int R,int v)
{
if(l>=L&&r<=R)
{
lazy[now]+=v;
sum[now]+=(ll)(r-l+1)*v;
return;
}
int mid=(l+r)>>1;
if(L<=mid)
update(l,mid,lson,L,R,v);
if(R>mid)
update(mid+1,r,rson,L,R,v);
sum[now]=sum[lson]+sum[rson]+(ll)(r-l+1)*lazy[now];
}
ll query(int l,int r,int now,int L,int R)
{
if(l>=L&&r<=R)
return sum[now];
int mid=(l+r)>>1;
ll re=(ll)(min(r,R)-max(l,L)+1)*lazy[now];
if(L<=mid)
re+=query(l,mid,lson,L,R);
if(R>mid)
re+=query(mid+1,r,rson,L,R);
return re;
}
int main()
{
// setIO("input");
int i,j,tot=0;
scanf("%d%d",&n,&Q);
for(i=1;i<=n;++i)
scanf("%d",&A[i]);
A[0]=n+1,A[n+1]=n+1,S.push(0);
for(i=1;i<=n;++i) s[i].mid=i;
for(i=1;i<=n;++i)
{
while(!S.empty()&&A[S.top()]<A[i])
S.pop();
s[i].l=S.top()+1;
S.push(i);
}
while(!S.empty()) S.pop();
S.push(n+1);
for(i=n;i>=1;--i)
{
while(!S.empty()&&A[S.top()]<A[i])
S.pop();
s[i].r=S.top()-1;
S.push(i);
}
for(i=1;i<=Q;++i) scanf("%d",&lp[i]);
for(i=1;i<=Q;++i) scanf("%d",&rp[i]);
for(i=1;i<=Q;++i)
{
if(lp[i]-1)
{
as[++tot].mid=lp[i]-1;
as[tot].l=lp[i];
as[tot].r=rp[i];
as[tot].id=i;
as[tot].opt=-1;
}
as[++tot].mid=rp[i];
as[tot].l=lp[i];
as[tot].r=rp[i];
as[tot].id=i;
as[tot].opt=1;
}
sort(as+1,as+1+tot,cmp);
for(j=i=1;i<=tot;++i)
{
while(j<=as[i].mid&&j<=n) {
update(1,n,1,s[j].l,s[j].r,1);
++j;
}
ll cu=query(1,n,1,as[i].l,as[i].r);
ans[as[i].id]+=as[i].opt*cu;
}
for(i=1;i<=Q;++i)
{
printf("%lld ",ans[i]);
}
return 0;
}