前言
HNOI作为Hard NOI,题目质量还是很高的(扯淡)
其中考查的数据结构非常简单,但是很锻炼思维能力.
正题
一开始看到时空限制想试试莫队
O
(
n
∗
n
)
O(n*\sqrt n)
O(n∗n),但是好像不行.
然后,推出一堆结论就去看题解了
设
L
[
i
]
,
R
[
i
]
表
示
值
大
于
k
i
的
左
右
最
近
位
置
L[i],R[i]表示值大于k_i的左右最近位置
L[i],R[i]表示值大于ki的左右最近位置
则对于产生
p
1
p1
p1贡献当且仅当:
- ( i , i + 1 ) , i ∈ [ a , b ) (i,i+1),i\in[a,b) (i,i+1),i∈[a,b)
- a ≤ L [ i ] a n d R [ i ] ≤ b a n d i ∈ ( a , b ) a\le L[i]~~ and ~R[i]\le b~~ and ~~ i\in (a,b) a≤L[i] and R[i]≤b and i∈(a,b)
对于产生
p
2
p2
p2贡献的次数为满足以下条件的次数:(
j
∈
[
a
,
b
]
j\in [a,b]
j∈[a,b])
(
i
,
j
,
k
)
,
i
<
j
<
k
,
m
a
x
(
L
[
j
]
,
a
−
1
)
<
i
,
k
<
m
i
n
(
R
[
j
]
,
b
−
1
)
(i,j,k),i<j<k,max(L[j],a-1)<i,k<min(R[j],b-1)
(i,j,k),i<j<k,max(L[j],a−1)<i,k<min(R[j],b−1)
更具体的实现方式:
当扫到
R
[
i
]
R[i]
R[i]时,把
L
[
i
]
L[i]
L[i]的贡献加
p
1
p1
p1,把
[
L
[
i
]
+
1
,
i
−
1
]
[L[i]+1,i-1]
[L[i]+1,i−1]的贡献加
p
2
p2
p2
当扫到
L
[
i
]
L[i]
L[i]时,把
[
i
+
1
,
R
[
i
]
]
[i+1,R[i]]
[i+1,R[i]]的贡献加
p
2
p2
p2.
处理方法:
顺序处理每个位置的贡献,那么询问
[
l
,
r
]
[l,r]
[l,r]的答案就是
(
r
时
的
答
案
)
−
(
l
−
1
时
的
答
案
)
(r时的答案)-(l-1时的答案)
(r时的答案)−(l−1时的答案).(用树状数组维护前缀和)
就是排除掉前
l
−
1
l-1
l−1个位置的影响.
ps:auto 是c++11以上才有的
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
using namespace std;
typedef long long ll;
const int N=2e5+10,size=1<<20;
//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
char c=gc; x=0; int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
while(isdigit(c)) x=x*10+c-'0',c=gc;
x*=f;
}
template<class o> void qw(o x) {
if(x/10) qw(x/10);
putchar(x%10+'0');
}
template<class o> void pr2(o x) {
if(x<0)x=-x,putchar('-');
qw(x); puts("");
}
int n,m,p1,p2,a[N],L[N],R[N],sta[N],top;
ll c1[N],c2[N],ans[N];
void add(int x,int y) {
ll z=(ll)x*y;
if(x)while(x<=n) c1[x]+=y,c2[x]+=z,x+=x&-x;
}
ll ask(int x) {
ll s=0;
for(int i=x; i;i-=i&-i) s+=(x+1)*c1[i]-c2[i];
return s;
}
struct node {
int l,r,id,d;
};
vector<node> q[N],o[N];//query,option
int main() {
qr(n); qr(m); qr(p1); qr(p2); a[0]=a[n+1]=n+1;
for(int i=1;i<=n;i++) {
qr(a[i]);
while(a[sta[top]]<a[i]) R[sta[top--]]=i;
L[i]=sta[top]; sta[++top]=i;
}
while(top) R[sta[top--]]=n+1;
for(int i=1,l,r;i<=m;i++) {
qr(l); qr(r);
q[r].push_back((node){l,r,i,1});
q[l-1].push_back((node){l,r,i,-1});
ans[i]=(r-l)*p1;
}
for(int i=1,l,r;i<=n;i++) {
l=L[i]; r=R[i];
if(i+1<=r-1)o[l].push_back((node){i+1,r-1,0,p2});
if(l) o[r].push_back((node){l,l,0,p1});
if(l+1<=i-1)o[r].push_back((node){l+1,i-1,0,p2});
}
for(int i=1;i<=n;i++) {
for(auto now:o[i])
add(now.r+1,-now.d),
add(now.l,now.d);
for(auto now:q[i])
ans[now.id]+=now.d*(ask(now.r)-ask(now.l-1));
}
for(int i=1;i<=m;i++) pr2(ans[i]);
return 0;
}