title
简化题意:
一个长度为 \(n\) 的序列,如果对于两个位置 \(l,r\),他们是区间 \([l,r]\) 中的最大值和次大值,产生 \(p_1\) 的贡献;如果恰好有一个是最大值,产生 \(p_2\) 的贡献。
analysis
让我想起了冯·霍恩海姆。
看了半天题面,尝试自己概括题意,抽出模型,然而...
这题面真的不是人话,所以我就去看了 yyb 的 \(blog\) ,这才看懂了题意。
发现这两个贡献的条件是有重叠的,即这个区间的一个端点一定是这个区间的最大值,那就只有先把这个处理出来,才能做下面的工作。
即处理出每个点 \(i\) 左边第一个比它大的点 \(L[i]\) ,和右边第一个比它大的点 \(R[i]\) ,这个可以用一个单调栈扫两遍就好了。
那么
- 那么对于区间 \(L[i]\) 到 \(R[i]\) 有 \(p_1\) 的贡献;
- 对于左端点在 \(L[i]+1\sim i-1\) ,右端点为 \(R[i]\) 的区间有 \(p_2\) 的贡献;
- 对于左端点为 \(L[i]\) ,右端点为 \(i+1\sim R[i]-1\) 的区间也有 \(p_2\) 的贡献。
所以可以离线处理一下。
然后
- 我们在扫到 \(R[i]\) 时,更新点 \(L[i]\) 的贡献;
- 我们在扫到 \(R[i]\) 时,更新区间 \(L[i]+1\sim i-1\) 的贡献;
- 我们在扫到 \(L[i]\) 时,更新区间 \(i+1\sim R[i]-1\) 的贡献。
这样就与处理好所有区间的贡献了。
那么对于每个询问 \([l,r]\) ,把上面的三种情况全部抽象成二维平面上的线段1,那么询问就相当于求这个区间内的权值和,用扫描线和区间修改 \(BIT\) 可以完成这个操作。
code
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=2e5+10;
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x,char str)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++=str;
}
}
using IO::read;
using IO::write;
int n,m,p1,p2;
namespace BIT
{
ll c1[maxn],c2[maxn];
inline int lowbit(int x) { return x & -x; }
inline void add(int x,int v) { for (int i=x; i<=n; i+=lowbit(i)) c1[i]+=v, c2[i]+=x*v; }
inline ll ask(int x) { ll ans=0; for (int i=x; i; i-=lowbit(i)) ans+=(x+1)*c1[i]-c2[i]; return ans; }
inline ll hsh(int l,int r) { return ask(r)-ask(l-1); }
}
using BIT::add;
using BIT::hsh;
struct QwQ{int x,l,r,v,id;}q[maxn<<2];
int cnt;
inline bool cmp1(QwQ a,QwQ b) { return a.x<b.x; }
struct Orz{int x,l,r,v;}o[maxn<<2];
int tot;
inline bool cmp2(Orz a,Orz b) { return a.x<b.x; }
ll ans[maxn]; int L[maxn],R[maxn];
int k[maxn],Stack[maxn],top;
int main()
{
read(n);read(m);read(p1);read(p2);
for (int i=1; i<=n; ++i) read(k[i]);
Stack[top=1]=0;
for (int i=1; i<=n; ++i)
{
while (top>1 && k[Stack[top]]<k[i]) --top;
L[i]=Stack[top], Stack[++top]=i;
}
Stack[top=1]=n+1;
for (int i=n; i>=1; --i)
{
while (top>1 && k[Stack[top]]<k[i]) --top;
R[i]=Stack[top], Stack[++top]=i;
}
for (int i=1,l,r; i<=m; ++i)
{
read(l);read(r);
ans[i]=(r-l)*p1;
q[++cnt]=(QwQ){r,l,r,1,i};
q[++cnt]=(QwQ){l-1,l,r,-1,i};
}
std::sort(q+1,q+cnt+1,cmp1);
for (int i=1; i<=n; ++i)
{
if (L[i] && R[i]<n+1) o[++tot]=(Orz){R[i],L[i],L[i],p1};
if (L[i] && R[i]>i+1) o[++tot]=(Orz){L[i],i+1,R[i]-1,p2};
if (L[i]+1<i && R[i]<n+1) o[++tot]=(Orz){R[i],L[i]+1,i-1,p2};
}
std::sort(o+1,o+tot+1,cmp2);
for (int i=1, j=1; i<=cnt; ++i)
{
while (j<=tot && o[j].x<=q[i].x) add(o[j].l,o[j].v), add(o[j].r+1,-o[j].v), ++j;
ans[q[i].id]+=q[i].v*hsh(q[i].l,q[i].r);
}
for (int i=1; i<=m; ++i) write(ans[i],'\n');
IO::flush();
return 0;
}