题解:
这个题可以采取离线处理的方式.先处理出每个点i左边第一个比它大的点L[i],和右边第一个比它大的点R[i].
那么对于区间L[i]到R[i]有p1的贡献.①
对于左端点在L[i]+1到i-1,右端点为R[i]的区间有p2的贡献.②
对于左端点为L[i],右端点为i+1到R[i]-1的区间也有p2的贡献.③
所以我们离线排序处理好.
对于①情况,我们在扫到R[i]时,更新点L[i]的贡献
对于②情况,我们在扫到R[i]时,更新区间L[i]+1到i-1的贡献
对于③情况,我们在扫到L[i]时,更新区间i+1到R[i]-1的贡献
我们对于每个询问[l,r],在扫到l-1时,我们记录此时区间l到r的每个点的贡献和为sum1,然后当我们扫到r的时候,再次记录此时的区间l到r的每个点的贡献和为sum2,显然答案就是sum2-sum1了.
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstring> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #define RG register 11 #define LL long long int 12 #define MAXN 500010 13 using namespace std; 14 const int INF=1e9; 15 struct node{ 16 int l,r,x,id,v; 17 node(){} 18 node(int l_,int r_,int x_,int id_,int v_):l(l_),r(r_),x(x_),id(id_),v(v_){} 19 bool operator <(const node &tmp)const{ 20 return x<tmp.x; 21 } 22 }s1[MAXN],s2[MAXN]; 23 int n,m,p1,p2; 24 int k[MAXN],q[MAXN],top; 25 int L[MAXN],R[MAXN]; 26 LL ans[MAXN],c1[MAXN],c2[MAXN]; 27 int lowbit(int x) 28 { 29 return x&(-x); 30 } 31 void add(int x,int y)//区间修改操作 32 { 33 if(x) for(int i=x;i<=n;i+=lowbit(i)) c1[i]+=y,c2[i]+=(LL)x*y; 34 } 35 LL sum(int x) 36 { 37 LL num=0; 38 for(int i=x;i>0;i-=lowbit(i)) num+=(x+1)*c1[i]-c2[i]; 39 return num; 40 } 41 int main() 42 { 43 freopen("1.in","r",stdin); 44 scanf("%d%d%d%d",&n,&m,&p1,&p2); 45 k[0]=k[n+1]=n+1;q[++top]=0; 46 for(int i=1;i<=n;i++) scanf("%d",&k[i]); 47 for(int i=1;i<=n+1;i++) 48 { 49 while(k[q[top]]<k[i]) R[q[top]]=i,top--; 50 L[i]=q[top];q[++top]=i; 51 } 52 int x,y; 53 for(int i=1;i<=m;i++) 54 { 55 scanf("%d%d",&x,&y);ans[i]+=(y-x)*p1; 56 s1[i]=node(x,y,x-1,i,-1);s1[i+m]=node(x,y,y,i,1); 57 } 58 sort(s1+1,s1+2*m+1);int tot=0; 59 for(int i=1;i<=n;i++) 60 { 61 if(1<=L[i]&&R[i]<=n) s2[++tot]=node(L[i],L[i],R[i],0,p1); 62 if(1<=L[i]&&R[i]>i+1) s2[++tot]=node(i+1,R[i]-1,L[i],0,p2); 63 if(L[i]+1<i&&R[i]<=n) s2[++tot]=node(L[i]+1,i-1,R[i],0,p2); 64 } 65 sort(s2+1,s2+tot+1);int n1=1,n2=1; 66 while(!s1[n1].x) n1++; 67 for(int i=1;n1<=m*2&&i<=n;i++) 68 { 69 while(n2<=tot&&s2[n2].x==i){ 70 add(s2[n2].r+1,-s2[n2].v); 71 add(s2[n2].l,s2[n2].v); 72 n2++; 73 } 74 while(n1<=m*2&&s1[n1].x==i){ 75 ans[s1[n1].id]+=s1[n1].v*(sum(s1[n1].r)-sum(s1[n1].l-1)); 76 n1++; 77 } 78 } 79 for(int i=1;i<=m;i++) printf("%lld ",ans[i]); 80 return 0; 81 }