显然先用单调栈求出一个位置向左/右延申的最大长度(即这些区间中当前位置是最大值位置)
然后我们发现我们可以离线,然后按照最大值位置依次添加线段,每次用线段树查一个区间和.
然后我们想查满足最大值位置在 $[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; }