题目描述
影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样
的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠
这些战斗力提升自己的攻击。奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。
第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i,j(i
做法
来看看到底要统计什么?对于(i,j)满足
i<j
如果
max(a[i+1~j-1])
<
<script type="math/tex" id="MathJax-Element-685"><</script>min(a[i],a[j])
这样有t1个,贡献就是t1*p1。
如果
min(a[i],a[j])
<
<script type="math/tex" id="MathJax-Element-686"><</script>max(a[i+1~j-1])
<
<script type="math/tex" id="MathJax-Element-687"><</script>max(a[i],a[j])
这样有t2个,贡献就是t2*p2。
这个t2不是很好算,考虑转化成
max(a[i+1~j-1]
<
<script type="math/tex" id="MathJax-Element-688"><</script>max(a[i],a[j])
然后减掉第一种情况
考虑对每个点i,求出left[i]和right[i]表示往左和往右第一个大于自己的位置。
对于第一种,枚举一个i作为较小的位置,较大的位置j只能是left[i]或right[i]。
对于第二种,枚举一个i作为较大的位置,较小的位置j只能夹在left[i]和i或i和right[i]之间。
第一种的式子
∑ri=l[left[i]>=l]+[right[i]<=r]
第二种的式子
∑ri=l(i−max(left[i],l−1)−1)+(min(right[i],r+1)−i−1)
这个计算,拿个主席树。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=200000+10,maxtot=5000000+10;
int a[maxn],left[maxn],right[maxn],ask[maxn][2],id[maxn];
int root[maxn],size[maxtot],tree[maxtot][2],sta[80];
ll num[maxtot],sum[maxtot];
ll cnt[maxn][2],ans,x,ans1,ans2,ans3;
int i,j,k,l,r,t,n,m,p1,p2,top,tot;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
bool cmp1(int x,int y){
return left[x]>left[y];
}
bool cmp2(int x,int y){
return right[x]<right[y];
}
int newnode(int x){
++tot;
tree[tot][0]=tree[x][0];
tree[tot][1]=tree[x][1];
size[tot]=size[x];
num[tot]=num[x];
sum[tot]=sum[x];
return tot;
}
void insert(int &x,int l,int r,int a,int p){
x=newnode(x);
if (l==r){
size[x]++;
num[x]+=(ll)l;
sum[x]+=p?(ll)right[l]:(ll)left[l];
return;
}
int mid=(l+r)/2;
if (a<=mid) insert(tree[x][0],l,mid,a,p);else insert(tree[x][1],mid+1,r,a,p);
size[x]=size[tree[x][0]]+size[tree[x][1]];
num[x]=num[tree[x][0]]+num[tree[x][1]];
sum[x]=sum[tree[x][0]]+sum[tree[x][1]];
}
void query(int x,int l,int r,int a,int b){
if (!x) return;
if (l==a&&r==b){
ans1+=size[x];
ans2+=num[x];
ans3+=sum[x];
return;
}
int mid=(l+r)/2;
if (b<=mid) query(tree[x][0],l,mid,a,b);
else if (a>mid) query(tree[x][1],mid+1,r,a,b);
else{
query(tree[x][0],l,mid,a,mid);
query(tree[x][1],mid+1,r,mid+1,b);
}
}
ll getsum(int n){
return (ll)n*(n+1)/2;
}
void write(ll x){
if (!x){
putchar('0');
putchar('\n');
return;
}
top=0;
while (x){
sta[++top]=x%10;
x/=10;
}
while (top) putchar('0'+sta[top--]);
putchar('\n');
}
int main(){
freopen("sf.in","r",stdin);freopen("sf.out","w",stdout);
n=read();m=read();p1=read();p2=read();
fo(i,1,n) a[i]=read();
fo(i,1,m) ask[i][0]=read(),ask[i][1]=read();
fo(i,1,n){
j=i-1;
while (j&&a[j]<a[i]) j=left[j];
left[i]=j;
}
fd(i,n,1){
j=i+1;
while (j<=n&&a[j]<a[i]) j=right[j];
right[i]=j;
}
fo(i,1,n) id[i]=i;
sort(id+1,id+n+1,cmp1);
tot=0;
j=1;
fd(i,n,1){
root[i]=root[i+1];
k=j-1;
while (k<n&&left[id[k+1]]==i) k++;
fo(t,j,k) insert(root[i],1,n,id[t],0);
j=k+1;
}
fo(i,1,m){
l=ask[i][0];r=ask[i][1];
ans1=ans2=ans3=0;
query(root[l],1,n,l,r);
cnt[i][0]+=ans1;
cnt[i][1]+=ans2-ans3-ans1;
ans1=(r-l+1)-ans1;
ans2=getsum(r)-getsum(l-1)-ans2;
cnt[i][1]+=ans2-(ll)ans1*l;
}
fo(i,1,tot)
tree[i][0]=tree[i][1]=size[i]=sum[i]=num[i]=0;
tot=0;
fo(i,1,n) id[i]=i;
sort(id+1,id+n+1,cmp2);
tot=0;
j=1;
fo(i,1,n){
root[i]=root[i-1];
k=j-1;
while (k<n&&right[id[k+1]]==i) k++;
fo(t,j,k) insert(root[i],1,n,id[t],1);
j=k+1;
}
fo(i,1,m){
l=ask[i][0];r=ask[i][1];
ans1=ans2=ans3=0;
query(root[r],1,n,l,r);
cnt[i][0]+=ans1;
cnt[i][1]+=ans3-ans2-ans1;
ans1=(r-l+1)-ans1;
ans2=getsum(r)-getsum(l-1)-ans2;
cnt[i][1]+=(ll)ans1*r-ans2;
}
fo(i,1,m){
l=ask[i][0];r=ask[i][1];
cnt[i][1]-=cnt[i][0];
ans=(ll)p1*cnt[i][0];
ans+=(ll)p2*cnt[i][1];
write(ans);
}
}