题目链接:影魔
这道题就是去年序列的弱化版啊……
我们枚举最大值的位置\(i\),找出左边第一个比\(a_i\)大的位置\(l\),右边第一个比\(a_i\)大的位置\(r\),然后我们分开考虑一下\(p_1\)和\(p_2\)的贡献。
首先由于\(a_i\)为最大值,那么左端点不会小于\(l\),右端点不会大于\(r\)。
容易发现只有左端点为\(l\),右端点为\(r\)才会产生\(p_1\)的贡献。
然后产生\(p_2\)贡献的有两种:一种是左端点为\(l\),右端点在区间\((i,r)\)中;另一种是左端点区间\((l,i)\)中,右端点为\(r\)。
所以这个问题可以抽象到二维平面上。有一些点和一些线段都有权值,每次询问某个矩形内部的权值和。
于是离线排序+扫描线+树状数组即可。
下面贴代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define maxn 200010 using namespace std; typedef long long llg; struct Segment{ int l,r,x,b,z; bool operator < (const Segment &h)const{return x<h.x;} }s1[maxn<<1],s2[maxn*3]; int n,m,p1,p2,S[maxn],top,ls; int a[maxn],le[maxn],ri[maxn]; llg ans[maxn],c1[maxn],c2[maxn]; int getint(){ int w=0;bool q=0; char c=getchar(); while((c>‘9‘||c<‘0‘)&&c!=‘-‘) c=getchar(); if(c==‘-‘) c=getchar(),q=1; while(c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar(); return q?-w:w; } void add(int x,int y){if(x)for(int i=x;i<=n;i+=i&(-i)) c1[i]+=y,c2[i]+=1ll*x*y;} llg sum(int x){ llg t=0; for(int i=x;i;i-=i&(-i)) t+=(x+1)*c1[i]-c2[i]; return t; } int main(){ File("sf"); n=getint(),m=getint(),p1=getint(),p2=getint(); for(int i=1;i<=n;i++) a[i]=getint(); a[0]=a[n+1]=n+1; S[top=1]=0; for(int i=1;i<=n;i++){ while(a[S[top]]<a[i]) top--; le[i]=S[top]; S[++top]=i; } S[top=1]=n+1; for(int i=n;i>=1;i--){ while(a[S[top]]<a[i]) top--; ri[i]=S[top]; S[++top]=i; } for(int i=1,l,r;i<=m;i++){ l=getint(),r=getint(); ans[i]+=1ll*(r-l)*p1; s1[i].l=l,s1[i].r=r,s1[i].x=l-1; s1[i].b=i,s1[i].z=-1; s1[i+m]=s1[i]; s1[i+m].x=r,s1[i+m].z=1; } sort(s1+1,s1+m*2+1); for(int i=1;i<=n;i++){ if(le[i] && ri[i]<=n){ ls++; s2[ls].x=ri[i]; s2[ls].z=p1; s2[ls].l=s2[ls].r=le[i]; } if(le[i] && ri[i]>i+1){ ls++; s2[ls].x=le[i]; s2[ls].z=p2; s2[ls].l=i+1,s2[ls].r=ri[i]-1; } if(ri[i]<=n && i>le[i]+1){ ls++; s2[ls].x=ri[i]; s2[ls].z=p2; s2[ls].l=le[i]+1,s2[ls].r=i-1; } } sort(s2+1,s2+ls+1); int n1=1,n2=1; while(!s1[n1].x) n1++; for(int i=1;n1<=m*2 && i<=n;i++){ while(n2<=ls && s2[n2].x==i){ add(s2[n2].r+1,-s2[n2].z); add(s2[n2].l,s2[n2].z),n2++; } while(n1<=m*2 && s1[n1].x==i){ ans[s1[n1].b]+=s1[n1].z*(sum(s1[n1].r)-sum(s1[n1].l-1)); n1++; } } for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }
时间: 2024-10-08 08:15:59