分析:直接贴题解了:
对每个点i,单调栈求出左边和右边第一个大于i的位置,记为l[i]和r[i]
那么(l[i],r[i])会产生p1的贡献
左端点为l[i],右端点在[i+1,r-1]的点对都会产生p2的贡献(原来题解笔误了)
右端点为r[i],左端点在[l+1,i-1]的点对都会产生p2的贡献
将点对看成平面上的点,横坐标左端点纵坐标右端点,上述贡献分别对应单点加(p1)和线段加(p2)
查询就是矩形求和
主席树开两颗维护一下就好,注意把相同的横坐标的用模拟链表存一下。
所以。。这题千万要注意程序常数啊!!!!!!!!!!!!我日,主席树被卡翻了,被卡了一个下午,把所有的define全部换回去加上快速读入才能过。。。出题人你要这样??(╯‵□′)╯︵┻━┻
ccz大爷的笛卡尔树+扫描线速度快,码量少,艹飞主席树,然而我并不会打笛卡尔(╯‵□′)╯︵┻━┻
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
#define N 200010
#define M 20000010
using namespace std;
typedef long long ll;
struct node
{
int l,r,v;
}t[N*4];
int head[N],cnt;
int n,m,p1,p2;
int a[N];
ll v[M],key[M];
int stack[N],top;
int from[N*4];
int lson[M],rson[M],l[N],r[N],Left[N],Right[N];
int tot;
inline int read()
{
int k=0;
char f=1;
char c=getchar();
for(;!isdigit(c);c=getchar() )
if(c=='-')
f=-1;
for(;isdigit(c);c=getchar() )
k=k*10+c-'0';
return k*f;
}
inline void add(int x,int l,int r,int v){
from[++cnt]=head[x];
head[x]=cnt;
t[cnt].l=l;
t[cnt].r=r;
t[cnt].v=v;
}
inline void change(int &x,int last,int l1,int r1,int l,int r,int val)
{
if(l>r) return ;
x=++tot;
v[x]=v[last];
key[x]=key[last];
lson[x]=lson[last];
rson[x]=rson[last];
v[x]+=1ll*(r-l+1)*val;
if(l1==l&&r1==r)
{
key[x]+=val;
return ;
}
int mid=(l1+r1)>>1;
if(r<=mid)
change(lson[x],lson[last],l1,mid,l,r,val);
else if(l>mid)
change(rson[x],rson[last],mid+1,r1,l,r,val);
else
change(lson[x],lson[last],l1,mid,l,mid,val),
change(rson[x],rson[last],mid+1,r1,mid+1,r,val);
}
ll query(int x,int l1,int r1,int l,int r){
if(!x){
return 0;
}
if(l1==l&&r1==r){
return v[x];
}
ll ans=key[x]*(r-l+1);
int mid=l1+r1>>1;
if(r<=mid) return ans+query(lson[x],l1,mid,l,r);
else if(l>mid)return ans+query(rson[x],mid+1,r1,l,r);
else return ans+query(lson[x],l1,mid,l,mid)+query(rson[x],mid+1,r1,mid+1,r);
}
int main()
{
freopen("sf.in","r",stdin);
freopen("sf.out","w",stdout);
n=read();m=read();
p1=read();p2=read();
int i;
for(i=1;i<=n;i++)
a[i]=read();
for(i=1;i<=n;i++)
{
while(top&&a[stack[top]]<a[i])top--;
l[i]=stack[top]+1;
stack[++top]=i;
}
stack[top=0]=n+1;
for(i=n;i;i--)
{
while(top&&a[stack[top]]<a[i])top--;
r[i]=stack[top]-1;
stack[++top]=i;
}
for(i=1;i<=n;i++)
{
add(l[i]-1,r[i]+1,r[i]+1,p1);
add(l[i]-1,i+1,r[i],p2);
add(r[i]+1,l[i],i-1,p2);
}
int x;
for(x=1;x<=n;x++)
{
Left[x]=Left[x-1];
for(i=head[x];i;i=from[i])
if(t[i].l>x) change(Left[x],Left[x],1,n,max(1,t[i].l),min(n,t[i].r),t[i].v);
if(x!=n)change(Left[x],Left[x],1,n,x+1,x+1,p1);
}
for(x=n;x;x--)
{
Right[x]=Right[x+1];
for(i=head[x];i;i=from[i])
if(t[i].r<x)change(Right[x],Right[x],1,n,max(1,t[i].l),min(n,t[i].r),t[i].v);
}
while(m--)
{
int x,y;
x=read();y=read();
ll ans=0;
ans+=query(Left[y],1,n,x,y);
ans-=query(Left[x-1],1,n,x,y);
ans+=query(Right[x],1,n,x,y);
ans-=query(Right[y+1],1,n,x,y);
printf("%lld\n",ans);
}
return 0;
}