前言
HNOI作为Hard NOI,题目质量还是很高的(扯淡)
其中考查的数据结构非常简单,但是很锻炼思维能力.
正题
一开始看到时空限制想试试莫队
,但是好像不行.
然后,推出一堆结论就去看题解了
设
则对于产生
贡献当且仅当:
对于产生
贡献的次数为满足以下条件的次数:(
)
更具体的实现方式:
当扫到
时,把
的贡献加
,把
的贡献加
当扫到
时,把
的贡献加
.
处理方法:
顺序处理每个位置的贡献,那么询问
的答案就是
.(用树状数组维护前缀和)
就是排除掉前
个位置的影响.
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;
}