题意:
有n个点,横纵坐标都是
1−n
的排列,每次询问
[l,r]
,求在
[l,r]
中分别满足一下条件的点对
(i,j)
:
(定义
max(l,r)
为横坐标
l
到
1.
y[i]>max(l,r)且y[j]>max(l,r)
.
2.
y[i]>max(l,r)>y[j]或y[j]>max(l,r)>y[i]
题解:
离线扫描线+树状数组。
先单调栈找出左右第一个纵坐标大于 y[i] 的 L[i],R[i]
首先,对于第一种情况,设有
y[i]<y[j]
那么
j
只能是
证明:若不是,则两点间有一点纵坐标大于
y[i]
。
对于第二种情况,容易发现所有情况都包含在了对于每个
i
的
然后把所有合法的点对看做点或者是线段。扫描线一遍即可。
(出题人丧心病狂的卡了线段树,所以学了树状数组的区间加减查询:http://www.cnblogs.com/lcf-2000/p/5866170.html#3773822)
#include<bits/stdc++.h>
using namespace std;
struct IO
{
streambuf *ib,*ob;
int buf[50];
inline void init()
{
ios::sync_with_stdio(false);
cin.tie(NULL);cout.tie(NULL);
ib=cin.rdbuf();ob=cout.rdbuf();
}
inline int read()
{
char ch=ib->sbumpc();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=ib->sbumpc();}
return i*f;
}
inline void W(long long x)
{
if(!x){ob->sputc('0');return;}
if(x<0){ob->sputc('-');x=-x;}
while(x){buf[++buf[0]]=x%10,x/=10;}
while(buf[0]){ob->sputc(buf[buf[0]--]+'0');}
}
}io;
const int Maxn=2e5+50;
int n,m,p1,p2,L[Maxn],R[Maxn],K[Maxn];
long long ans[Maxn];
struct Segment
{
int l,r;
Segment(int l,int r):l(l),r(r){}
};
inline int lowbit(int pos){return pos&(-pos);}
struct BIT
{
long long d1[Maxn],d2[Maxn];
inline long long asksum(int x)
{
long long res1=0,res2=0;
for(int pos=x;pos;pos-=lowbit(pos))res1+=d1[pos],res2+=d2[pos];
return res1*(x+1)-res2;
}
inline long long query(int l,int r){return asksum(r)-asksum(l-1);}
inline void modify(int l,int r)
{
for(int pos=l;pos<=n;pos+=lowbit(pos))d1[pos]++,d2[pos]+=l;
for(int pos=r+1;pos<=n;pos+=lowbit(pos))d1[pos]--,d2[pos]-=(r+1);
}
}t1,t2;
struct Q
{
int l,r,id,bz;
Q(int l=0,int r=0,int id=0,int bz=0):l(l),r(r),id(id),bz(bz){}
};
vector<Segment>data2[Maxn];
vector<int>data[Maxn];
vector<Q>query[Maxn];
inline void GetL(int *a)
{
static int st[Maxn],pos[Maxn],tail;
pos[1]=1,st[1]=K[1];tail=1;
for(int i=2;i<=n;i++)
{
while(st[tail]<K[i]&&tail)a[pos[tail--]]=i;
st[++tail]=K[i],pos[tail]=i;
}
while(tail)a[pos[tail--]]=n+1;
}
int main()
{
io.init();n=io.read(),m=io.read(),p1=io.read(),p2=io.read();
for(int i=1;i<=n;i++)K[i]=io.read();
GetL(R);reverse(K+1,K+n+1);
GetL(L);reverse(L+1,L+n+1);
for(int i=1;i<=n;i++)L[i]=n-L[i]+1;
for(int i=1;i<=n;i++)
{
if(L[i])data[i].push_back(L[i]);
if(R[i]!=n+1)data[i].push_back(R[i]);
if(L[i]&&R[i]>i+1)data2[L[i]].push_back(Segment(i+1,R[i]-1));
if(R[i]!=n+1&&L[i]<i-1)data2[R[i]].push_back(Segment(L[i]+1,i-1));
}
for(int i=1;i<=m;i++)
{
int l=io.read(),r=io.read();l--;
if(l)query[l].push_back(Q(l+1,r,i,-1));
query[r].push_back(Q(l+1,r,i,1));
}
for(int i=1;i<=n;i++)
{
for(int e=data[i].size()-1;e>=0;e--)t1.modify(data[i][e],data[i][e]);
for(int e=data2[i].size()-1;e>=0;e--)t2.modify(data2[i][e].l,data2[i][e].r);
for(int e=query[i].size()-1;e>=0;e--)
{
ans[query[i][e].id]+=1ll*p1*query[i][e].bz*t1.query(query[i][e].l,query[i][e].r);
ans[query[i][e].id]+=1ll*p2*query[i][e].bz*t2.query(query[i][e].l,query[i][e].r);
}
}
for(int i=1;i<=m;i++)io.W(ans[i]),io.ob->sputc('\n');
}