[AH2017/HNOI2017]影魔
30pts
暴力在每个区间中枚举点对 ( a , b ) (a,b) (a,b)并查询点对之间的最大值 m a x max max,若 m a x < = m i n ( a , b ) max<=min(a,b) max<=min(a,b)则贡献 p 1 p1 p1,若 m i n ( a , b ) < m a x < m a x ( a , b ) min(a,b)<max<max(a,b) min(a,b)<max<max(a,b)则贡 p 2 p2 p2
60pts的tip
这个
p
1
=
2
∗
p
2
p1=2*p2
p1=2∗p2提醒我们什么事情?当我们查询到
m
a
x
max
max时,我们做了一个判断,若
a
,
b
a,b
a,b中有两个数大于
m
a
x
max
max则贡献
p
1
p1
p1,若只有一个数大于
m
a
x
max
max就贡献
p
2
p2
p2,所以我们发现这两种情况其实是有关联的。于是我们又发现了一件事情,我们对于每一对
(
a
,
b
)
(a,b)
(a,b),只关心其中的
m
a
x
max
max,并不关心其他数,所以我们考虑枚举中间那个
m
a
x
max
max,然后找到
m
a
x
max
max左/右边比他大的第一个位置
l
[
i
]
/
r
[
i
]
l[i]/r[i]
l[i]/r[i],那么就有以下三种情况:
1,区间
[
l
[
i
]
,
r
[
i
]
−
1
]
,
[
l
[
i
]
,
r
[
i
]
−
2
]
,
.
.
.
,
[
l
[
i
]
,
i
+
1
]
[l[i],r[i]-1],[l[i],r[i]-2],...,[l[i],i+1]
[l[i],r[i]−1],[l[i],r[i]−2],...,[l[i],i+1]这些区间都能贡献
p
2
p2
p2
2,区间
[
l
[
i
]
+
1
,
r
[
i
]
]
,
[
l
[
i
]
+
2
,
r
[
i
]
]
,
.
.
.
,
[
i
−
1
,
r
[
i
]
]
[l[i]+1,r[i]],[l[i]+2,r[i]],...,[i-1,r[i]]
[l[i]+1,r[i]],[l[i]+2,r[i]],...,[i−1,r[i]]这些区间都能贡献
p
2
p2
p2
3,区间
[
l
[
i
]
,
r
[
i
]
]
[l[i],r[i]]
[l[i],r[i]]可以贡献一个
p
1
p1
p1
其实到这里只剩复杂度优化的问题了
100pts
离线处理,对于上述三种情况有以下:
1,这一类区间左端点固定,将询问按照左端点排序,从右往左扫,如果遇到一个
l
[
i
]
l[i]
l[i]就在线段树上把区间
[
i
+
1
,
r
[
i
]
−
1
]
[i+1,r[i]-1]
[i+1,r[i]−1]全部加上
p
2
p2
p2,如果遇到一个询问的左端点L,就在线段树上查询
[
L
,
R
]
[L,R]
[L,R]的和
2,几乎同上,反着做一遍
3,两边扫都可以,在线段树上可以包含贡献区间的位置区间加上,扫的过程中单点查询即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+5;
int n,m,a[N],l[N],r[N];
ll t[N<<2],tag[N<<2],p1,p2;
stack <int> Q;
struct query
{
int l,r,id;
ll ans;
}q[N];
struct data
{
int pos,l,r;
}f[N];
bool cmpa(const data x,const data y)
{
return x.l<y.l;
}
bool cmpb(const data x,const data y)
{
return x.r<y.r;
}
bool cmp1(const query x,const query y)
{
return x.l<y.l;
}
bool cmp2(const query x,const query y)
{
return x.r<y.r;
}
bool cmp3(const query x,const query y)
{
return x.id<y.id;
}
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
int Read()
{
ll x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
void Get_lr()
{
a[0]=a[n+1]=n+1;
while (Q.size()) Q.pop();
Q.push(0);
for (int i=1;i<=n;i++)
{
while (Q.size()&&a[i]>a[Q.top()]) Q.pop();
l[i]=Q.top();
Q.push(i);
}
while (Q.size()) Q.pop();
Q.push(n+1);
for (int i=n;i>=1;i--)
{
while (Q.size()&&a[i]>a[Q.top()]) Q.pop();
r[i]=Q.top();
Q.push(i);
}
for (int i=1;i<=n;i++) f[i]=(data){i,l[i],r[i]};
return;
}
void Pushdown(int p,int ls,int rs,int l,int r)
{
if (!tag[p]) return;
int mid=(l+r)>>1;
tag[ls]+=tag[p];
tag[rs]+=tag[p];
t[ls]+=tag[p]*(mid-l+1);
t[rs]+=tag[p]*(r-(mid+1)+1);
tag[p]=0;
return;
}
void Modify(int p,int l,int r,int L,int R,ll v)
{
if (L<=l&&r<=R)
{
t[p]+=v*(r-l+1);
tag[p]+=v;
return;
}
int ls=p<<1,rs=p<<1|1,mid=(l+r)>>1;
Pushdown(p,ls,rs,l,r);
if (L<=mid) Modify(ls,l,mid,L,R,v);
if (R>mid) Modify(rs,mid+1,r,L,R,v);
t[p]=t[ls]+t[rs];
return;
}
ll Query(int p,int l,int r,int L,int R)
{
if (L<=l&&r<=R) return t[p];
ll ret=0;
int ls=p<<1,rs=p<<1|1,mid=(l+r)>>1;
Pushdown(p,ls,rs,l,r);
if (L<=mid) ret+=Query(ls,l,mid,L,R);
if (R>mid) ret+=Query(rs,mid+1,r,L,R);
t[p]=t[ls]+t[rs];
return ret;
}
int Find1(int val)
{
int l=1,r=n,mid;
while (l<r)
{
mid=(l+r)>>1;
if (f[mid].l>=val) r=mid;
else l=mid+1;
}
return l;
}
int Find2(int val)
{
int l=1,r=n,mid;
while (l<r)
{
mid=(l+r+1)>>1;
if (f[mid].r<=val) l=mid;
else r=mid-1;
}
return l;
}
void Solve()
{
//case 1
memset(t,0,sizeof(t));
memset(tag,0,sizeof(tag));
sort(q+1,q+m+1,cmp1);
sort(f+1,f+n+1,cmpa);
int now=n+1;
for (int i=m;i>=1;i--)
{
int tmp;
tmp=Find1(q[i].l);
for (int j=now-1;j>=tmp;j--)
if (f[j].pos+1<=f[j].r-1) Modify(1,0,n+1,f[j].pos+1,f[j].r-1,p2);
now=tmp;
q[i].ans+=Query(1,0,n+1,q[i].l,q[i].r);
}
//case 2
memset(t,0,sizeof(t));
memset(tag,0,sizeof(tag));
sort(q+1,q+m+1,cmp2);
sort(f+1,f+n+1,cmpb);
now=0;
for (int i=1;i<=m;i++)
{
int tmp;
tmp=Find2(q[i].r);
for (int j=now+1;j<=tmp;j++)
if (f[j].l+1<=f[j].pos-1) Modify(1,0,n+1,f[j].l+1,f[j].pos-1,p2);
now=tmp;
q[i].ans+=Query(1,0,n+1,q[i].l,q[i].r);
}
//case 3
memset(t,0,sizeof(t));
memset(tag,0,sizeof(tag));
sort(q+1,q+m+1,cmp2);
sort(f+1,f+n+1,cmpb);
now=0;
for (int i=1;i<=m;i++)
{
int tmp;
tmp=Find2(q[i].r);
for (int j=now+1;j<=tmp;j++)
if (1<=f[j].l) Modify(1,0,n+1,1,f[j].l,p1);
now=tmp;
q[i].ans+=Query(1,0,n+1,q[i].l,q[i].l);
}
return;
}
int main()
{
n=read(),m=read(),p1=Read(),p2=Read();
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
Get_lr();
Solve();
sort(q+1,q+m+1,cmp3);
for (int i=1;i<=m;i++) q[i].ans+=(q[i].r-q[i].l)*p1,printf("%lld\n",q[i].ans);
return 0;
}