Description
影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。
每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。
奈文摩尔有n个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号1到n。第i个灵魂的战斗力为k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对i,j
(i<j)
来说,若不存在
k[s](i<s<j)
大于k[i]或者k[j],则会为影魔提供p1的攻击力(可理解为:当j=i+1时,因为不存在满足
i<s<j
的s,从而k[s]不存在,这时提供p1的攻击力;当j>i+1时,若
maxk[s]|i<s<j<=mink[i],k[j]
,则提供p1的攻击力);另一种情况,令c为k[i+1],k[i+2],k[i+3]……k[j-1]的最大值,若c满足:
k[i]<c<k[j]
,或者
k[j]<c<k[i]
,则会为影魔提供p2的攻击力,当这样的c不存在时,自然不会提供这p2的攻击力;其他情况的点对,均不会为影魔提供攻击力。
影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间[a,b],
1<=a<b<=n
,位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑所有满足
a<=i<j<=b
的灵魂对i,j提供的攻击力之和。
顺带一提,灵魂的战斗力组成一个1到n的排列:k[1],k[2],…,k[n]。
Input
输入文件名为sf.in。
第一行n,m,p1,p2
第二行n个数:k[1],k[2],…,k[n]
接下来m行,每行两个数a,b,表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。
Output
输出文件名为sf.out
共输出m行,每行一个答案,依次对应m个询问。
Sample Input
10 5 2 3
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
Sample Output
30
39
4
13
16
Data Constraint
30%:1<= n,m <= 500。
另30%: p1=2*p2。
100%:1 <= n,m <= 200000;1 <= p1,p2 <= 1000。
题解
正常一点的解法就是主席树强行维护一波咯,但是我并不会区间加入(为什么我怎么想都觉得会爆空间呢?),本来以为这题不可改,但是良心的题解提供了另外一种很优秀的解法
我们考虑用扫描线来解决这个问题,我们可以把某一个点作为左端点和右端点的贡献(而且是较高的那个端点)分开来考虑
首先用单调栈处理出每一个点的下一个和上一个比它高的位置
设为next[i]以及last[i]
对于左端点:
假设我们当前的扫描线扫描到了i,那么我们就先钦定[i+1,next[i]]这一段都获得p2的贡献,而在next[i]右边的点肯定是和i没有关系的,就算有(比如说比next[i]还要高的点)也会在计算以那个点为右端点的时候被计算到,这样就可以巧妙的去重了
然后是关键,如果有next[i],我们将它单点加p1-2*p2,为什么要这样加呢?
我们可以用一个例子来解释
设现在有两个位置i,j且这个点对的贡献为p1,由于给的序列是一个排列,所以肯定有其中一个大于另外一个
那么以i为左端点以及以j为右端点时都会给对方p2的贡献,加起来也就是2*p2,所以我们要把它约掉,然后再加上p1
最后由于我们是扫描线,所以说每次做之前要先把询问数组拍一下序,然后对于左端点,我们从右到左扫,贡献就是当前线段树的[1,q[i,2]]这些叶子节点的贡献和,类似的,对于右端点,我们的扫描线从左往右扫,贡献就是[q[i,1],n]
其实主要的思路就是先通过扫描线搞定其中的一个限制,然后把贡献放在线段树上与另外一个限制有关的位置放上相应的贡献,通过区间的操作维护答案
贴代码
var
tree,lazy:array[0..700005]of int64;
next,last,gt,st:array[0..200005]of longint;
ans:array[0..200005]of int64;
q:array[0..200005,1..3]of longint;
i,j,k,l,m,n,p1,p2,x,y,z,p:longint;
tot:int64;
procedure qsort(l,r:longint);
var
i,j,mid:longint;
begin
i:=l;
j:=r;
mid:=q[(i+j) div 2,1];
repeat
while q[i,1]<mid do inc(i);
while q[j,1]>mid do dec(j);
if i<=j then
begin
q[0]:=q[i];
q[i]:=q[j];
q[j]:=q[0];
inc(i);
dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
procedure qsort1(l,r:longint);
var
i,j,mid:longint;
begin
i:=l;
j:=r;
mid:=q[(i+j) div 2,2];
repeat
while q[i,2]<mid do inc(i);
while q[j,2]>mid do dec(j);
if i<=j then
begin
q[0]:=q[i];
q[i]:=q[j];
q[j]:=q[0];
inc(i);
dec(j);
end;
until i>j;
if i<r then qsort1(i,r);
if l<j then qsort1(l,j);
end;
procedure fi(l,r,v:longint);
begin
tree[v]:=tree[v]+(r-l+1)*lazy[v];
if l<>r then
begin
inc(lazy[v*2],lazy[v]);
inc(lazy[v*2+1],lazy[v]);
end;
lazy[v]:=0;
end;
procedure change(v,l,r,x,y,z:longint);
var
mid:longint;
begin
tree[v]:=tree[v]+(r-l+1)*lazy[v];
if l<>r then
begin
inc(lazy[v*2],lazy[v]);
inc(lazy[v*2+1],lazy[v]);
end;
lazy[v]:=0;
if (l=x) and (r=y) then
begin
tree[v]:=tree[v]+(r-l+1)*z;
if l<>r then
begin
lazy[v*2]:=lazy[v*2]+z;
lazy[v*2+1]:=lazy[v*2+1]+z;
end;
end
else
begin
mid:=(l+r) div 2;
if y<=mid then change(v*2,l,mid,x,y,z) else
if x>mid then change(v*2+1,mid+1,r,x,y,z) else
begin
change(v*2,l,mid,x,mid,z);
change(v*2+1,mid+1,r,mid+1,y,z);
end;
if lazy[v*2+1]<>0 then
begin
fi(mid+1,r,v*2+1);
end;
if lazy[v*2]<>0 then fi(l,mid,v*2);
tree[v]:=tree[v*2]+tree[v*2+1];
end;
end;
procedure find(v,l,r,x,y:longint);
var
mid:longint;
begin
tree[v]:=tree[v]+(r-l+1)*lazy[v];
if l<>r then
begin
inc(lazy[v*2],lazy[v]);
inc(lazy[v*2+1],lazy[v]);
end;
lazy[v]:=0;
if (l=x) and (r=y) then tot:=tot+tree[v] else
begin
mid:=(l+r) div 2;
if y<=mid then find(v*2,l,mid,x,y) else
if x>mid then find(v*2+1,mid+1,r,x,y) else
begin
find(v*2,l,mid,x,mid);
find(v*2+1,mid+1,r,mid+1,y);
end;
end;
end;
begin
assign(input,'sf.in'); reset(input);
assign(output,'sf.out'); rewrite(output);
readln(n,m,p1,p2);
for i:=1 to n do read(gt[i]);
readln;
x:=1;
st[1]:=1;
for i:=2 to n do
begin
while (gt[i]>gt[st[x]]) and (x>0) do
begin
next[st[x]]:=i;
dec(x);
end;
inc(x);
st[x]:=i;
end;
x:=1;
st[1]:=n;
for i:=n-1 downto 1 do
begin
while (gt[i]>gt[st[x]]) and (x>0) do
begin
last[st[x]]:=i;
dec(x);
end;
inc(x);
st[x]:=i;
end;
for i:=1 to m do readln(q[i,1],q[i,2]);
for i:=1 to m do q[i,3]:=i;
qsort(1,m);
x:=m;
for i:=n downto 1 do
begin
if next[i]<>0 then
begin
change(1,1,n,i+1,next[i],p2);
change(1,1,n,next[i],next[i],p1-2*p2);
end else
if i<>n then
change(1,1,n,i+1,n,p2);
while i=q[x,1] do
begin
tot:=0;
find(1,1,n,1,q[x,2]);
ans[q[x,3]]:=ans[q[x,3]]+tot;
dec(x);
if x=0 then break;
end;
if x=0 then break;
end;
fillchar(tree,sizeof(tree),0);
fillchar(lazy,sizeof(lazy),0);
qsort1(1,m);
x:=1;
for i:=1 to n do
begin
if last[i]<>0 then
begin
change(1,1,n,last[i],i-1,p2);
change(1,1,n,last[i],last[i],p1-2*p2);
end else
if i<>1 then
change(1,1,n,1,i-1,p2);
while i=q[x,2] do
begin
tot:=0;
find(1,1,n,q[x,1],n);
ans[q[x,3]]:=ans[q[x,3]]+tot;
inc(x);
if x>m then break;
end;
if x>m then break;
end;
for i:=1 to m do writeln(ans[i]);
close(input); close(output);
end.