传送门
首先整个序列是一个排列,这是一个很重要的性质
考虑 ( i , j ) (i,j) (i,j)什么时候会产生贡献:
维护出每个 i i i位置左边右边第一个比它大的位置,记作 L i , R i L_i,R_i Li,Ri,这个可以用单调栈求。于是 ( L i , R i ) (L_i,R_i) (Li,Ri), ( i , i + 1 ) (i,i+1) (i,i+1)的贡献为 p 1 p1 p1, ( L i + 1... i − 1 , R i ) (L_i+1...i-1,R_i) (Li+1...i−1,Ri), ( L i , i + 1... R i − 1 ) (L_i,i+1...R_i-1) (Li,i+1...Ri−1)的贡献为 p 2 p2 p2
可以发现如果有 ( p , q ) (p,q) (p,q)满足 p < L i , q < R i p
对于 ( i , i + 1 ) (i,i+1) (i,i+1),直接根据询问区间长度算贡献
对于 ( L i , R i ) (L_i,R_i) (Li,Ri),我们在枚举到 R i R_i Ri时在 L i L_i Li上加上贡献
对于 ( L i + 1... i − 1 , R i ) (L_i+1...i-1,R_i) (Li+1...i−1,Ri),我们在枚举到 R i R_i Ri时在 L i + 1... i − 1 L_i+1...i-1 Li+1...i−1这段区间加上贡献
对于 ( L i , i + 1... R i ) (L_i,i+1...R_i) (Li,i+1...Ri),同上一条
回答一个询问 [ a , b ] [a,b] [a,b]时,如果在枚举到 b b b时直接求 [ a , b ] [a,b] [a,b]的区间和,会存在一些 ( i , j ) (i,j) (i,j)满足 i < a , a < j < b ii<a,a<j<b的不合法的贡献。所以我们需要减去枚举到 a − 1 a-1 a−1时 [ a , b ] [a,b] [a,b]的区间和,这样有贡献的 ( i , j ) (i,j) (i,j)就都在区间内
C o d e B e l o w Code Below CodeBelow
#include
#define ts cout<<"ok"<
#define int long long
#define hh puts("")
#define pc putchar
#define ls(x) ((x)<<1)
#define rs(x) ((x)<<1|1)
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
using namespace std;
const int N=200005;
int n,m,p1,p2,a[N],st[N],top,L[N],R[N],cnt,tot;
int tr[N<<2],tag[N<<2],ans[N];
struct que{
int x,l,r,v,id;
friend bool operator < (que A,que B){
return A.x<B.x;
}
}q[N<<1];
struct ope{
int x,l,r,v;
friend bool operator < (ope A,ope B){
return A.x<B.x;
}
}op[N<<2];
inline int read(){
int ret=0,ff=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)){ret=ret*10+(ch^48);ch=getchar();}
return ret*ff;
}
void write(int x){if(x<0){x=-x,pc('-');}if(x>9) write(x/10);pc(x%10+48);}
void writeln(int x){write(x),hh;}
void writesp(int x){write(x),pc(' ');}
void push_down(int l,int r,int k){
int mid=(l+r)>>1;
tag[ls(k)]+=tag[k];
tag[rs(k)]+=tag[k];
tr[ls(k)]+=tag[k]*(mid-l+1);
tr[rs(k)]+=tag[k]*(r-mid);
tag[k]=0;
}
void update(int l,int r,int x,int y,int v,int k){
if(x<=l&&r<=y){
tr[k]+=(r-l+1)*v;
tag[k]+=v;
return;
}
push_down(l,r,k);
int mid=(l+r)>>1;
if(x<=mid) update(l,mid,x,y,v,ls(k));
if(mid+1<=y) update(mid+1,r,x,y,v,rs(k));
tr[k]=tr[ls(k)]+tr[rs(k)];
}
int query(int l,int r,int x,int y,int k){
if(x<=l&&r<=y) return tr[k];
push_down(l,r,k);
int mid=(l+r)>>1,res=0;
if(x<=mid) res+=query(l,mid,x,y,ls(k));
if(mid+1<=y) res+=query(mid+1,r,x,y,rs(k));
return res;
}
signed main(){
n=read(),m=read(),p1=read(),p2=read();
for(int i=1;i<=n;i++) a[i]=read();
st[top=0]=0;
for(int i=1;i<=n;i++){
while(top&&a[i]>a[st[top]]) top--;
L[i]=st[top];st[++top]=i;
}
st[top=0]=n+1;
for(int i=n;i>=1;i--){
while(top&&a[i]>a[st[top]]) top--;
R[i]=st[top];st[++top]=i;
}
for(int i=1;i<=m;i++){
int l=read(),r=read();ans[i]=(r-l)*p1;//(i,i+1)的贡献
q[++cnt]=(que){l-1,l,r,-1,i};
q[++cnt]=(que){r,l,r,1,i};
}
sort(q+1,q+cnt+1);
for(int i=1;i<=n;i++){
if(L[i]>=1&&R[i]<=n) op[++tot]=(ope){R[i],L[i],L[i],p1};
if(L[i]>=1&&R[i]-1>=i+1) op[++tot]=(ope){L[i],i+1,R[i]-1,p2};
if(L[i]+1<=i-1&&R[i]<=n) op[++tot]=(ope){R[i],L[i]+1,i-1,p2};
}
sort(op+1,op+tot+1);
for(int i=1,j=1;i<=cnt;i++){
while(j<=tot&&op[j].x<=q[i].x){
update(1,n,op[j].l,op[j].r,op[j].v,1);
j++;
}
ans[q[i].id]+=q[i].v*query(1,n,q[i].l,q[i].r,1);
}
for(int i=1;i<=m;i++) writeln(ans[i]);
return 0;
}