[BZOJ4540]序列
给出一个序列,求某段区间的位置不同子串的最小值之和
对于前$40%$,我们可以$n^{2}$预处然后$O(n\sqrt{n})$
预处理中$zzz[i][j]$表示以$i$开头,结尾最长到$j$的前缀子串的最小值之和
同理$fff[i][j]$表示倒过来的情况
考虑对预处理进行优化
对于一个区间$[l,r]$,以$l$开头,结尾最长到$r$的前缀可分为两部分计算,
设$x$为区间$[l,r]$中最小值所在位置
对于结尾在区间$[x,r]$中的子串,对答案的贡献为$A[x]*(r-x+1)$
对于结尾在区间$[l,x)$中的子串,我们先找到下一个比$A[l]$小的位置$p1$,则对于结尾在区间$[l,p1)$中的子串,对答案的贡献为$A[l]*(p1-l)$,再找到下一个比$A[p1]$小的位置$p2$类推,直到找到$x$为止
这就相当于对于一个数$A[x]$,我们把下一个比它小的数$A[y]$向它连边,边权为$A[x]*(y-x)$,然后求树上的节点$l$到$x$的距离和
这个过程我们可以通过维护单调栈预处理出来
$zzz[i]$表示节点到$i$所属的树根的距离,因为可能是森林
从后往前枚举,当前值小于等于栈顶时弹栈,然后$zzz[i]=zzz[sta[top]]+A[i]*(sta[top]-i)$
$fff[i]$同理
然后莫队,,,复杂度$O(nlogn+n\sqrt{n})$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define inf 0x3f3f3f3f 4 #define maxn 100005 5 typedef long long ll; 6 struct node{ int l,r,blc,id; ll ans; }q[maxn]; 7 int n,m,sta[maxn],mn[maxn<<1][20],log_2[maxn]; 8 ll A[maxn],fff[maxn],zzz[maxn]; 9 bool cmp1(node a,node b){ 10 if(a.blc!=b.blc)return a.blc<b.blc; 11 else if(a.r!=b.r)return a.r<b.r; 12 else return a.l<b.l; 13 } 14 bool cmp2(node a,node b){ return a.id<b.id; } 15 void PP(){ 16 int top=0; 17 for(int i=1;i<=n;i++){ 18 while(top&&A[i]<=A[sta[top]])top--; 19 fff[i]=fff[sta[top]]+A[i]*(i-sta[top]); 20 sta[++top]=i; 21 } 22 sta[top=0]=n+1; 23 for(int i=n;i;i--){ 24 while(top&&A[i]<=A[sta[top]])top--; 25 zzz[i]=zzz[sta[top]]+A[i]*(sta[top]-i); 26 sta[++top]=i; 27 } 28 } 29 int Min(int x,int y){ 30 return A[x]<A[y]?x:y; 31 } 32 void build_ST(){ 33 A[0]=inf; 34 for(int i=1;i<=n;i++) 35 mn[i][0]=i; 36 log_2[1]=0; 37 for(int i=2;i<=n;i++) 38 log_2[i]=log_2[i>>1]+1; 39 for(int j=1;j<=log_2[n];j++) 40 for(int i=1;i<=n;i++) 41 mn[i][j]=Min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]); 42 } 43 int query_ST(int l,int r){ 44 int len=log_2[r-l+1]; 45 return Min(mn[l][len],mn[r-(1<<len)+1][len]); 46 } 47 ll call(int l,int r){ 48 int x=query_ST(l,r); 49 return A[x]*(r-x+1)+zzz[l]-zzz[x]; 50 } 51 ll calr(int l,int r){ 52 int x=query_ST(l,r); 53 return A[x]*(x-l+1)+fff[r]-fff[x]; 54 } 55 void MD(){ 56 sort(q+1,q+1+m,cmp1); 57 int l=1,r=0; 58 ll ans=0; 59 for(int i=1;i<=m;i++){ 60 while(r<q[i].r)ans+=calr(l,++r); 61 while(r>q[i].r)ans-=calr(l,r--); 62 while(l>q[i].l)ans+=call(--l,r); 63 while(l<q[i].l)ans-=call(l++,r); 64 q[i].ans=ans; 65 } 66 sort(q+1,q+1+m,cmp2); 67 for(int i=1;i<=m;i++) 68 printf("%lld\n",q[i].ans); 69 } 70 int main(){ 71 scanf("%d%d",&n,&m); 72 for(int i=1;i<=n;i++) 73 scanf("%lld",&A[i]); 74 PP(),build_ST(); 75 int block=sqrt(n); 76 for(int i=1;i<=m;i++){ 77 scanf("%d%d",&q[i].l,&q[i].r); 78 q[i].blc=(q[i].l-1)/block+1,q[i].id=i; 79 } 80 MD(); 81 return 0; 82 }