[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 }
View Code

 

posted @ 2016-04-19 18:39  Ngshily  阅读(804)  评论(0编辑  收藏  举报