Link
Diffculty
算法难度6,思维难度6,代码难度7
Description
给定一个长度为 n n n的排列 A A A。
对于一个区间 [ L , R ] ( L < R ) [L,R](L<R) [L,R](L<R),如果 m a x ( A L + 1 , A L + 2 , … , A R − 1 ) < m i n ( A L , A R ) max(A_{L+1},A_{L+2},…,A_{R-1})<min(A_L,A_R) max(AL+1,AL+2,…,AR−1)<min(AL,AR),那么它的价值为 p 1 p1 p1
如果 m a x ( A L + 1 , A L + 2 , … , A R − 1 ) max(A_{L+1},A_{L+2},…,A_{R-1}) max(AL+1,AL+2,…,AR−1)小于 A L A_L AL和 A R A_R AR中的其中一个,那么它的价值为 p 2 p2 p2
否则区间价值为 0 0 0。
有 m m m个询问,给定 [ a , b ] [a,b] [a,b],询问 a ≤ L < b , a < R ≤ b a\le L<b,a<R\le b a≤L<b,a<R≤b的所有区间价值和。
1 ≤ n , m ≤ 2 × 1 0 5 , 1 ≤ p 1 , p 2 ≤ 1000 1\le n,m\le 2\times 10^5,1\le p1,p2\le 1000 1≤n,m≤2×105,1≤p1,p2≤1000
Solution
神仙题。。。
我们考虑把每个区间放在它的最大值处统计。
首先我们求出第 i i i个数左右边第一个大于它的值的位置 L e f t i , R i g h t i Left_i,Right_i Lefti,Righti
那么区间 [ L e f t i , R i g h t i ] [Left_i,Right_i] [Lefti,Righti]满足 p 1 p1 p1的价值。
假如固定左端点的话,区间 [ L e f t i , k ] , i < k < R i g h t i [Left_i,k],i<k<Right_i [Lefti,k],i<k<Righti都满足 p 2 p2 p2了。
同理 [ k , R i g h t i ] , L e f t i < k < i [k,Right_i],Left_i<k<i [k,Righti],Lefti<k<i也都满足 p 2 p2 p2了。
我们考虑一旦左端点越过 L e f t i Left_i Lefti,那么就不符合把区间放在最大值处统计了,右端点同理。
这样我们可以做到统计所有合法区间而且不统计不合法区间,也就是不重不漏了。
现在,我们考虑如何利用推出的这些东西来计算答案。
我们考虑建立二维平面, ( x , y ) (x,y) (x,y)这个点代表 [ x , y ] [x,y] [x,y]这个区间。
那么上面的那三个部分就都可以表示为点或者线段了。
询问则可以表示为一个正方形。
我们可以两遍扫描线+线段树出解。
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=2e5+5;
LL sum[N<<2],add[N<<2],Len[N<<2];
inline void pushdown(int rt){
if(add[rt]){
sum[rt<<1]+=add[rt]*Len[rt<<1];
sum[rt<<1|1]+=add[rt]*Len[rt<<1|1];
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
add[rt]=0;
}
}
inline void build(int rt,int l,int r){
Len[rt]=r-l+1;
sum[rt]=add[rt]=0;
if(l==r)return;
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
}
inline void modify(int rt,int l,int r,int L,int R,int v){
if(L>R)return;
if(L<=l && r<=R){
sum[rt]+=v*Len[rt];
add[rt]+=v;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid)modify(rt<<1,l,mid,L,R,v);
if(mid+1<=R)modify(rt<<1|1,mid+1,r,L,R,v);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
inline LL query(int rt,int l,int r,int L,int R){
if(L<=l && r<=R)return sum[rt];
pushdown(rt);
int mid=(l+r)>>1;LL ans=0;
if(L<=mid)ans+=query(rt<<1,l,mid,L,R);
if(mid+1<=R)ans+=query(rt<<1|1,mid+1,r,L,R);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
return ans;
}
struct data{
int id,x,y1,y2,v;
inline bool operator < (const data& b) const {
if(x==b.x)return id<b.id;
return x<b.x;
}
}q[N<<2],q2[N<<2];
LL ans[N],p1,p2;
int n,m,cnt,cnt2;
int a[N],Log[N],st[N][18];
int Left[N],Right[N];
int main(){
n=read();m=read();p1=read();p2=read();
for(int i=1;i<=n;++i)a[i]=read(),st[i][0]=a[i];
a[0]=st[0][0]=1e9;
a[n+1]=st[n+1][0]=1e9;
Log[0]=-1;
for(int i=1;i<=n+2;++i)Log[i]=Log[i>>1]+1;
for(int k=1;k<=17;++k)
for(int i=0;i+(1<<k)-1<=n+1;++i)
st[i][k]=max(st[i][k-1],st[i+(1<<(k-1))][k-1]);
for(int i=1;i<=n;++i){
int l=0,r=i-1,mid;
while(l<r){
mid=(l+r)>>1;
int k=Log[i-mid];
int num=max(st[mid+1][k],st[i-(1<<k)+1][k]);
if(num>a[i])l=mid+1;
else r=mid;
}
Left[i]=l;
l=i+1,r=n+1;
while(l<r){
mid=(l+r)>>1;
int k=Log[mid-i+1];
int num=max(st[i][k],st[mid-(1<<k)+1][k]);
if(num>a[i])r=mid;
else l=mid+1;
}
Right[i]=l;
q[++cnt]=(data){0,Left[i],Right[i],Right[i],p1};
q[++cnt]=(data){0,Left[i],i+1,Right[i]-1,p2};
q2[++cnt2]=(data){0,Right[i],Left[i]+1,i-1,p2};
}
for(int i=1;i<=m;++i){
int a=read(),b=read();
ans[i]=p1*(b-a);
q[++cnt]=(data){i,a-1,a,b,-1};
q[++cnt]=(data){i,b,a,b,1};
q2[++cnt2]=(data){i,a-1,a,b,-1};
q2[++cnt2]=(data){i,b,a,b,1};
}
sort(q+1,q+cnt+1);
sort(q2+1,q2+cnt2+1);
build(1,0,n+1);
for(int i=1;i<=cnt;++i){
if(q[i].id)ans[q[i].id]+=query(1,0,n+1,q[i].y1,q[i].y2)*q[i].v;
else modify(1,0,n+1,q[i].y1,q[i].y2,q[i].v);
}
build(1,0,n+1);
for(int i=1;i<=cnt2;++i){
if(q2[i].id)ans[q2[i].id]+=query(1,0,n+1,q2[i].y1,q2[i].y2)*q2[i].v;
else modify(1,0,n+1,q2[i].y1,q2[i].y2,q2[i].v);
}
for(int i=1;i<=m;++i)printf("%lld\n",ans[i]);
return 0;
}