标签:clu cdb span 题解 题意 关系 pen \n std
题意:每次询问一个区间[l,r],问[l,r]中的每一对(i,j)能够贡献多少总加成?给定序列a是1~n的一个排列,也就是a[i]两两不同。
设z=max{a[i+1],a[i+2],...,a[j-1]},若z<min(a[i],a[j]),加成p1;若min(a[i],a[j])<z<max(a[i],a[j]),加成p2。n<=20W。
标程:
1 #include<bits/stdc++.h> 2 #define mid ((l+r)>>1) 3 #define P pair<int,ll> 4 #define fir first 5 #define sec second 6 using namespace std; 7 typedef long long ll; 8 int read() 9 { 10 int x=0,f=1;char ch=getchar(); 11 while (ch<‘0‘||ch>‘9‘) {if (ch==‘-‘) f=-1;ch=getchar();} 12 while (ch>=‘0‘&&ch<=‘9‘) x=(x<<1)+(x<<3)+ch-‘0‘,ch=getchar(); 13 return x*f; 14 } 15 const int N=200005; 16 int rt1[N],rt2[N],sc,num[N*40],ls[N*40],rs[N*40],n,m,lf[N],rg[N],p1,p2,top,a[N],q[N]; 17 ll sum[N*40]; 18 P operator + (P a,P b) {return P(a.fir+b.fir,a.sec+b.sec);} 19 void ins(int &k,int pk,int l,int r,int x) 20 { 21 k=++sc;ls[k]=ls[pk];rs[k]=rs[pk]; 22 if (l==r) {sum[k]=sum[pk]+x;num[k]=num[pk]+1;return;} 23 if (x<=mid) ins(ls[k],ls[pk],l,mid,x); 24 else ins(rs[k],rs[pk],mid+1,r,x); 25 sum[k]=sum[ls[k]]+sum[rs[k]]; 26 num[k]=num[ls[k]]+num[rs[k]]; 27 } 28 P qry(int k1,int k2,int l,int r,int L,int R) 29 { 30 if (!k1) return P(0,0);//if(!k2)跳出P(num[k1],sum[k1])是不行的,考虑区间要在[L,R]内 31 if (L<=l&&r<=R) return P(num[k1]-num[k2],sum[k1]-sum[k2]); 32 P res=P(0,0); 33 if (L<=mid) res=res+qry(ls[k1],ls[k2],l,mid,L,R); 34 if (R>mid) res=res+qry(rs[k1],rs[k2],mid+1,r,L,R); 35 return res; 36 } 37 int main() 38 { 39 n=read();m=read();p1=read();p2=read(); 40 for (int i=1;i<=n;i++) a[i]=read(); 41 for (int i=1;i<=n;i++) 42 { 43 while (top>=1&&a[i]>a[q[top]]) top--; 44 lf[i]=q[top];q[++top]=i; 45 } 46 q[top=0]=n+1; 47 for (int i=n;i>=1;i--) 48 { 49 while (top>=1&&a[i]>a[q[top]]) top--; 50 rg[i]=q[top];q[++top]=i; 51 } 52 for (int i=1;i<=n;i++) 53 ins(rt1[i],rt1[i-1],0,n+1,lf[i]),ins(rt2[i],rt2[i-1],0,n+1,rg[i]); 54 while (m--) 55 { 56 int l,r; 57 l=read();r=read(); 58 P z1=qry(rt1[r],rt1[l-1],0,n+1,l,n); 59 P z2=qry(rt2[r],rt2[l-1],0,n+1,1,r); 60 ll x1=z1.fir+z2.fir; 61 ll x2=z2.sec-z1.sec+(ll)(r+1)*(r-l+1-z2.fir)-(ll)(l-1)*(r-l+1-z1.fir)-2*(r-l+1); 62 printf("%lld\n",(ll)p1*x1+(ll)p2*(x2-x1)); 63 } 64 return 0; 65 }
题解:计数+主席树
一开始卡在没有意识到计数时可以通过设置大小关系做到不重,一个区间只用统计到一个端点。
设[l,r]区间中满足限制1的有x1个,设满足z<max(a[i],a[j])限制2的有x2个(这样转化比较好求)。最后答案是x1*p1+(x2-x1)*p2。
考虑构造统计方式:对于每一个位置求出lf[i]和rg[i]表示左右离i位置最近的比它大的位置。
限制1:设i位置为较小端点,满足条件的端点只有lf[i]和rg[i]。式子:$\sum_{i=l}^{r}[lf[i]>=l]+[rg[i]<=r]$。
限制2:设i位置为较大端点,满足条件的是(lf[i],i)∪(i,rg[i])。式子:$\sum_{i=l}^{r}(min(rg[i],r+1)-max(lf[i],l-1)-2)$。权值主席树计算。
标签:clu cdb span 题解 题意 关系 pen \n std
原文地址:https://www.cnblogs.com/Scx117/p/9162659.html