[HNOI2016]序列(莫队,RMQ)
一眼看不出来怎么用数据结构维护
然后还没修改
所以考虑莫队
以$(l,r-1) -> (l,r)$为例
对答案的贡献是$Sigma_{i=l}^{r}minval(a[i:r])$
考虑维护前缀和
先用单调栈扫出$w[i]$作为最小值的左边界右边界$l_i,r_i$
然后回到上面的例子贡献就是$frontsum_{r}-frontsum_{rmqmin(l,r)}+w[rmqmin(l,r)]*(rmqmin(l,r)-l+1)$
完结...等等我好像忘了点啥
$frontsum_{i}$指的是从i向前拓展的i个包含i的子区间的区间最小值的和,也是可以用单调栈求出来的
时间复杂度略
#include<cstdio> #include<cmath> #include<algorithm> using std::sort; typedef long long lint; const int N=100011; template<typename tp>void read(tp &kk){ #define ak * tp phy=0,ioi=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')ioi=-1;ch=getchar();} while(ch>='0'&&ch<='9'){phy=phy*10+ch-'0';ch=getchar();} kk=phy ak ioi; } int n,m,bl[N]; lint w[N]; int bsize; int lg[N]; int lgl[N][17]; void is() { for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=n;i++) lgl[i][0]=i; for(int k=1;k<=lg[n];k++) { for(int i=1;i-1+(1<<k)<=n;i++) { lgl[i][k]=w[lgl[i][k-1]]<w[lgl[i+(1<<(k-1))][k-1]]?lgl[i][k-1]:lgl[i+(1<<(k-1))][k-1]; } } } int rmq(int l,int r){ return w[lgl[l][lg[r-l+1]]]< w[lgl[r-(1<<lg[r-l+1])+1][lg[r-l+1]]]? lgl[l][lg[r-l+1]]: lgl[r-(1<<lg[r-l+1])+1][lg[r-l+1]]; } int li[N],ri[N]; int st[N],hop; void rkk() { for(int i=1;i<=n;i++) { while(hop&&w[st[hop]]>w[i]) ri[st[hop]]=i-1,hop--; st[++hop]=i; if(i==n) while(hop) ri[st[hop]]=i,hop--; } for(int i=n;i;i--) { while(hop&&w[st[hop]]>w[i]) li[st[hop]]=i+1,hop--; st[++hop]=i; if(i==1) while(hop) li[st[hop]]=i,hop--; } } lint fsum[N],bsum[N]; void baka() { for(int i=1;i<=n;i++) fsum[i]=fsum[li[i]-1]+w[i]*(i-li[i]+1); for(int i=n;i;i--) bsum[i]=bsum[ri[i]+1]+w[i]*(ri[i]-i+1); } struct ques { int l,r,id; bool friend operator < (ques a,ques b) { if(bl[a.l]!=bl[b.l]) return bl[a.l]<bl[b.l]; return bl[a.r]<bl[b.r]; } }q[N]; lint prt[N],tmp; int main() { read(n),read(m),bsize=ceil(sqrt(n)); for(int i=1;i<=n;i++) read(w[i]),bl[i]=(i-1)/bsize+1; rkk(); is(); baka(); for(int i=1;i<=m;i++) read(q[i].l),read(q[i].r),q[i].id=i; sort(q+1,q+1+m); int l=1,r=1;tmp=w[1]; for(int i=1;i<=m;i++) { while(r<q[i].r){r++;tmp+=fsum[r]-fsum[rmq(l,r)]+((rmq(l,r)-l+1)*w[rmq(l,r)]);} while(l>q[i].l){l--;tmp+=bsum[l]-bsum[rmq(l,r)]+((r-rmq(l,r)+1)*w[rmq(l,r)]);} while(r>q[i].r){tmp-=fsum[r]-fsum[rmq(l,r)]+((rmq(l,r)-l+1)*w[rmq(l,r)]);r--;} while(l<q[i].l){tmp-=bsum[l]-bsum[rmq(l,r)]+((r-rmq(l,r)+1)*w[rmq(l,r)]);l++;} prt[q[i].id]=tmp; } for(int i=1;i<=m;i++) printf("%lld ",prt[i]); return 0; }