将区间[L,R]和点对(i,j)看作平面上的点,则询问为矩形求和
建出笛卡尔树,对应找出贡献为p1或p2的点,p1类的点总数为$O(n)$,p2类的点可以分为$O(n)$组,每组对应一条水平或竖直线段
最后用扫描线统计一下答案
#include<cstdio> #include<algorithm> typedef long long i64; const int N=200007; #define G *++ptr char buf[N*30],*ptr=buf-1; int _(){ int x=0,c=G; while(c<48)c=G; while(c>47)x=x*10+c-48,c=G; return x; } int n,m,p1,p2,a[N],ss[N],sp=0; int ch[N][2],lr[N][2]; i64 as[N]; i64 kb[N][2],bit[N][2]; void kb_add(int w,i64 k,i64 b){ for(;w<=n;w+=w&-w){ kb[w][0]+=k; kb[w][1]+=b; } } void kb_sum(int w,i64&_k,i64&_b){ i64 k=0,b=0; for(;w;w-=w&-w){ k+=kb[w][0]; b+=kb[w][1]; } _k=k;_b=b; } void add(int w,i64 a){ i64 b=a*(w-1); for(;w<=n;w+=w&-w){ bit[w][0]+=a; bit[w][1]+=b; } } i64 sum(int w){ i64 a=0,b=0,w0=w; for(;w;w-=w&-w){ a+=bit[w][0]; b+=bit[w][1]; } return a*w0-b; } struct Q{ int x,y,id; bool operator<(Q w)const{return x>w.x;} void work(){ i64 k,b; kb_sum(y,k,b); as[id]=sum(y)+k*x+b; } }qs[N]; struct E{ int x,y,tp,y2; bool operator<(E w)const{return x>w.x;} void work(){ if(tp==0){ kb_add(y,0,p1-p2); }else if(tp==1){ add(y,p2); add(y2+1,-p2); }else if(tp==2){ kb_add(y,-p2,i64(1+x)*p2); }else{ kb_add(y,p2,i64(-x-1)*p2); } } }es[N*8]; int ep=0; void dfs(int w){ int lc=ch[w][0],rc=ch[w][1]; lr[w][0]=lr[w][1]=w; if(lc){ dfs(lc); lr[w][0]=lr[lc][0]; es[ep++]=(E){lr[lc][1],w,2}; es[ep++]=(E){lr[lc][0]-1,w,3}; } if(rc){ dfs(rc); lr[w][1]=lr[rc][1]; es[ep++]=(E){w,lr[rc][0],1,lr[rc][1]}; } } int main(){ fread(buf,1,sizeof(buf),stdin)[buf]=0; n=_();m=_();p1=_();p2=_(); for(int i=1;i<=n;++i)a[i]=_(); for(int i=1;i<=n;++i){ ch[ss[sp]][1]=i; while(sp&&a[ss[sp]]<a[i]){ int w=ss[sp--]; ch[w][1]=ch[i][0]; ch[i][0]=w; ch[ss[sp]][1]=i; } ss[++sp]=i; } dfs(ch[0][1]); for(int w=1;w<=n;++w){ for(int u=ch[w][0];u;u=ch[u][1])es[ep++]=(E){u,w,0}; for(int u=ch[w][1];u;u=ch[u][0])es[ep++]=(E){w,u,0}; } std::sort(es,es+ep); for(int i=0;i<m;++i){ qs[i].x=_(); qs[i].y=_(); qs[i].id=i; } std::sort(qs,qs+m); for(int i=0,j=0;i<m;++i){ while(j<ep&&es[j].x>=qs[i].x)es[j++].work(); qs[i].work(); } for(int i=0;i<m;++i)printf("%lld\n",as[i]); return 0; }