版权声明:随意转载,愿意的话提一句作者就好了 https://blog.csdn.net/stone41123/article/details/84134286
Link
Diffculty
算法难度6,思维难度7,代码难度6
Description
给定一个长度为 的排列 。
对于一个区间 ,如果 ,那么它的价值为
如果 小于 和 中的其中一个,那么它的价值为
否则区间价值为 。
有 个询问,给定 ,询问 的所有区间价值和。
Solution
神仙题。。。
我们考虑把每个区间放在它的最大值处统计。
首先我们求出第 个数左右边第一个大于它的值的位置
那么区间 满足 的价值。
假如固定左端点的话,区间 都满足 了。
同理 也都满足 了。
我们考虑一旦左端点越过 ,那么就不符合把区间放在最大值处统计了,右端点同理。
这样我们可以做到统计所有合法区间而且不统计不合法区间,也就是不重不漏了。
现在,我们考虑如何利用推出的这些东西来计算答案。
我们考虑建立二维平面, 这个点代表 这个区间。
那么上面的那三个部分就都可以表示为点或者线段了。
询问则可以表示为一个正方形。
我们可以两遍扫描线+线段树出解。
时间复杂度
#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;
}