Problem
题外话
这道题有点类似于HNOI2016序列。好像并没有莫队做法,但是挺想打莫队的。。
Cai表示莫队被卡了:
Solution
先用单调栈处理出每个点的pre和nxt,即左边和右边第一个比更大的位置。
考虑对于点i,在区间[pre[i],nxt[i]]之间,p1只对于点对(pre[i],nxt[i])和相邻点对有贡献。当然了,pre[i]和i的贡献已经被区间内的点算过了(i和nxt[i]亦然)。
考虑p2的贡献,我们选取pre[i]和区间(i,nxt[i])之间可以做p2的贡献,等效的还有选取nxt[i]和区间(pre[i],i)之间的。
我们考虑按照坐标来进行扫描,因为如pre[i]和区间(i,nxt[i])做的p2贡献扫了l之后,还需要选取后面的数字才会生效,那么我们就设定一个生效坐标pos,作为排序依据。然后上支持区间修改的树状数组。
Code
#include <algorithm>
#include <cstdio>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
typedef long long ll;
const int maxn=200010;
int n,m,p1,p2,cnt,pre[maxn],nxt[maxn],a[maxn];
ll ans[maxn],t1[maxn],t2[maxn];
struct data{
int l,r,pos,id,val;
bool operator < (const data &x)const{return pos<x.pos;}
}q1[maxn<<1],q2[maxn*3];
struct STACK{
int tp,a[maxn];
void clear(){tp=0;}
int top(){return a[tp];}
void push(int val){a[++tp]=val;}
void pop(){tp--;}
}s;
template <typename Tp> inline void read(Tp &x)
{
x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
void input()
{
read(n);read(m);read(p1);read(p2);
s.clear();
for(int i=1;i<=n;i++)
{
read(a[i]);
while(s.tp&&a[s.top()]<a[i]) nxt[s.top()]=i,s.pop();
pre[i]=s.top();s.push(i);
}
while(s.tp) nxt[s.top()]=n+1,s.pop();
for(int i=1,l,r;i<=m;i++)
{
read(l);read(r);ans[i]+=(r-l)*p1;
q1[i]=(data){l,r,l-1,i,-1};q1[i+m]=(data){l,r,r,i,1};
}
sort(q1+1,q1+m+m+1);
}
void add(int pos,int val)
{
int ps=pos;
while(pos<=n)
{
t1[pos]+=val;t2[pos]+=(ll)ps*val;
pos+=lowbit(pos);
}
}
ll query(int pos)
{
ll res=0,ps=pos;
while(pos)
{
res+=(ps+1)*t1[pos]-t2[pos];
pos-=lowbit(pos);
}
return res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
input();
for(int i=1;i<=n;i++)
{
if(pre[i]&&nxt[i]<=n) q2[++cnt]=(data){pre[i],pre[i],nxt[i],0,p1};
if(pre[i]&&nxt[i]>i+1) q2[++cnt]=(data){i+1,nxt[i]-1,pre[i],0,p2};
if(nxt[i]<=n&&i>pre[i]+1) q2[++cnt]=(data){pre[i]+1,i-1,nxt[i],0,p2};
}
sort(q2+1,q2+cnt+1);
p1=p2=1;
while(!q1[p1].pos) p1++;
for(int i=1;p1<=m+m&&i<=n;i++)
{
while(p2<=cnt&&q2[p2].pos==i)
{
add(q2[p2].r+1,-q2[p2].val);
add(q2[p2].l,q2[p2].val);p2++;
}
while(p1<=m+m&&q1[p1].pos==i)
{
ans[q1[p1].id]+=q1[p1].val*(query(q1[p1].r)-query(q1[p1].l-1));
p1++;
}
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}