bzoj4540: [Hnoi2016]序列
Description
给定长度为n的序列:a1,a2,…,an,记为a[1:n]。类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-
1,ar。若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列。现在有q个询问,每个询问给定两个数l和r,1≤l≤r
≤n,求a[l:r]的不同子序列的最小值之和。例如,给定序列5,2,4,1,3,询问给定的两个数为1和3,那么a[1:3]有
6个子序列a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],这6个子序列的最小值之和为5+2+4+2+2+2=17。
Input
输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。接下来一行,包含n个整数,以空格隔开
,第i个整数为ai,即序列第i个元素的值。接下来q行,每行包含两个整数l和r,代表一次询问。
Output
对于每次询问,输出一行,代表询问的答案。
Sample Input
5 5
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5
Sample Output
28
17
11
11
17
17
11
11
17
HINT
1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9
题解:
此题有很多做法
1.第一种很naive,就是从n2暴力优化过来,但会被卡常数
设ans[i][j]表示i到j的最小值是多少,询问就是∑ans[i][j] (l<=i<=j<=r),做个二位前缀和即可
设最小的x满足在区间[ x , i ]中,a[i]是最小值(不严格,即在这个区间中可以有和a[i]相等的数),记作L[i]
设最大的y满足在区间[ i , y ]中,a[i]是最小值(严格,即在这个区间中不可以有和a[i]相等的数),记作R[i]
显然L[i]和R[i]都是可以用单调栈搞出来的
对于样例的ans数组如下
1 1 1 1 3
1 1 1 1
2 2 4
2 2
5
我们发现对于一个a[i],显然对于任意一个x和y,如果满足L[i]<=x<=i && i<=y<=R[i],那么ans[x][y]=a[i]
这显然是个矩形区域,而且询问也是,所以这可以用四分树做,复杂度为O( n log2 n ),但常数大,最慢的点要跑7s,所以不能通过此题……
2.第二种来源于claris另一道题的题解:http://www.cnblogs.com/clrs97/p/4824806.html
先将问题离线化,按右端点排序
我们发现上面那个ans数组每一行可以看成将上一行进行一次区间覆盖操作
而询问(l,r)的答案就是在第r行时,历史上所有sum[ l , r ]的和
通过线段树打标记维护,时间复杂度O( n log n )。
对于线段树上每个节点,维护以下信息:
v : 当前区间内所有数的和
s : 历史上所有v的和
l : 区间长度
a,b,c,d : 标记,分别表示生效之后
v'=a*v+b*l
s'=c*v+d*l+s
3.第三种是莫队算法
考虑假如已经知道了[ l , r ]的答案,将它减去所有左端点在 l 右端点在[ l , r ]的区间的最小值,就可以得到[ l + 1 , r ]的答案
显然右端点在 i 到 R[i] 的贡献为a[i] ,在R[i] + 1 到 R[ R[i] + 1 ] 的贡献为a[ R[i] + 1 ],...
以此类推,直到某个 p 的 R[p] + 1 > r ,剩下 p 到 r 的贡献为a[p]
暴力跳R[i]显然会T,我们发现,假如说定义a[ n + 1 ] = -inf 则每个点的下一个点都是确定的,这个形成了一个树形关系
我们将一个点 i 的父亲定义为R[i] + 1,与父亲连的边的边权为 a[i] * ( R[i] - i + 1 )
那么转移的时候先求出[ l , r ]中的最小值的位置p,答案将减去 dis[l] - dis[p] + a[p] * ( r - p + 1 )
其他转移类似
code:
第一种TLE:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 typedef long long int64; 8 char ch; 9 bool ok; 10 void read(int &x){ 11 ok=0; 12 for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 13 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 14 if (ok) x=-x; 15 } 16 const int inf=2147483647; 17 const int maxn=100005; 18 int n,q,a[maxn],x,y,l[maxn],r[maxn],top,stack[maxn]; 19 struct segx{ 20 int tot,root,son[16000000][4]; 21 int64 sum[16000000],tag[16000000]; 22 void init(){tot=root=1;} 23 void cover(int &k,int l1,int r1,int x1,int x2,int l2,int r2,int y1,int y2,int v){ 24 if (!k) k=++tot; 25 if (x1<=l1&&r1<=x2&&y1<=l2&&r2<=y2){tag[k]+=v,sum[k]+=1LL*v*(r1-l1+1)*(r2-l2+1);return;} 26 int m1=(l1+r1)>>1,m2=(l2+r2)>>1; 27 if (x1<=m1&&y1<=m2) cover(son[k][0],l1,m1,x1,x2,l2,m2,y1,y2,v); 28 if (x1<=m1&&m2<y2) cover(son[k][2],l1,m1,x1,x2,m2+1,r2,y1,y2,v); 29 if (m1<x2&&y1<=m2) cover(son[k][1],m1+1,r1,x1,x2,l2,m2,y1,y2,v); 30 if (m1<x2&&m2<y2) cover(son[k][3],m1+1,r1,x1,x2,m2+1,r2,y1,y2,v); 31 sum[k]=0; 32 for (int i=0;i<4;i++) sum[k]+=sum[son[k][i]]; 33 } 34 void cover(int x1,int x2,int y1,int y2,int v){cover(root,1,n,x1,x2,1,n,y1,y2,v);} 35 int64 query(int k,int l1,int r1,int x1,int x2,int l2,int r2,int y1,int y2,int64 t){ 36 if (!k) return t*(min(r1,x2)-max(l1,x1)+1)*(min(r2,y2)-max(l2,y1)+1); 37 if (x1<=l1&&r1<=x2&&y1<=l2&&r2<=y2) return sum[k]+t*(r1-l1+1)*(r2-l2+1); 38 int m1=(l1+r1)>>1,m2=(l2+r2)>>1; 39 int64 res=0; 40 if (x1<=m1&&y1<=m2) res+=query(son[k][0],l1,m1,x1,x2,l2,m2,y1,y2,t+tag[k]); 41 if (x1<=m1&&m2<y2) res+=query(son[k][2],l1,m1,x1,x2,m2+1,r2,y1,y2,t+tag[k]); 42 if (m1<x2&&y1<=m2) res+=query(son[k][1],m1+1,r1,x1,x2,l2,m2,y1,y2,t+tag[k]); 43 if (m1<x2&&m2<y2) res+=query(son[k][3],m1+1,r1,x1,x2,m2+1,r2,y1,y2,t+tag[k]); 44 return res; 45 } 46 int64 query(int x1,int x2,int y1,int y2){return query(root,1,n,x1,x2,1,n,y1,y2,0);} 47 }Tx; 48 int main(){ 49 read(n),read(q),Tx.init(); 50 for (int i=1;i<=n;i++) read(a[i]); 51 a[0]=a[n+1]=-inf; 52 stack[top=1]=0; 53 for (int i=1;i<=n;i++){ 54 while (top&&a[stack[top]]>=a[i]) top--; 55 l[i]=stack[top]+1; 56 stack[++top]=i; 57 } 58 stack[top=1]=n+1; 59 for (int i=n;i>=1;i--){ 60 while (top&&a[stack[top]]>a[i]) top--; 61 r[i]=stack[top]-1; 62 stack[++top]=i; 63 } 64 for (int i=1;i<=n;i++) Tx.cover(l[i],i,i,r[i],a[i]); 65 while (q--) read(x),read(y),printf("%lld\n",Tx.query(x,y,x,y)); 66 return 0; 67 }
第二种:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 typedef long long int64; 8 char ch; 9 bool ok; 10 void read(int &x){ 11 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 12 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 13 if (ok) x=-x; 14 } 15 const int maxn=100005; 16 const int inf=2147483647; 17 int n,q,a[maxn],stack[maxn],top; 18 int64 ans[maxn]; 19 struct Quer{ 20 int l,r,id; 21 void init(int i){read(l),read(r),id=i;} 22 }quer[maxn]; 23 bool cmp(const Quer &a,const Quer &b){return a.r<b.r;} 24 struct Data{ 25 int64 a,b,c,d; 26 void init(){a=1,b=c=d=0;} 27 }; 28 Data operator+(const Data &x,const Data &y){return (Data){x.a*y.a,x.b*y.a+y.b,y.c*x.a+x.c,y.c*x.b+x.d+y.d};} 29 struct Seg{ 30 #define ls k<<1 31 #define rs (k<<1)+1 32 int len[maxn<<2]; 33 int64 v[maxn<<2],s[maxn<<2]; 34 Data tag[maxn<<2]; 35 void addtag(int k,Data t){s[k]=t.c*v[k]+t.d*len[k]+s[k],v[k]=t.a*v[k]+t.b*len[k],tag[k]=tag[k]+t;} 36 void pushdown(int k){addtag(ls,tag[k]),addtag(rs,tag[k]),tag[k].init();} 37 void update(int k){v[k]=v[ls]+v[rs],s[k]=s[ls]+s[rs];} 38 void build(int k,int l,int r){ 39 tag[k].init(),len[k]=r-l+1; 40 if (l==r) return; 41 int m=(l+r)>>1; 42 build(ls,l,m),build(rs,m+1,r); 43 } 44 void cover(int k,int l,int r,int x,int y,Data t){ 45 if (l==x&&r==y){addtag(k,t);return;} 46 int m=(l+r)>>1; pushdown(k); 47 if (y<=m) cover(ls,l,m,x,y,t); 48 else if (x<=m) cover(ls,l,m,x,m,t),cover(rs,m+1,r,m+1,y,t); 49 else cover(rs,m+1,r,x,y,t); 50 update(k); 51 } 52 void cover(int x,int y,int v){cover(1,1,n,x,y,(Data){0,v,0,0}),addtag(1,(Data){1,0,1,0});} 53 int64 query(int k,int l,int r,int x,int y){ 54 if (l==x&&r==y) return s[k]; 55 int m=(l+r)>>1; pushdown(k); 56 if (y<=m) return query(ls,l,m,x,y); 57 else if (x<=m) return query(ls,l,m,x,m)+query(rs,m+1,r,m+1,y); 58 else return query(rs,m+1,r,x,y); 59 } 60 int64 query(int x,int y){return query(1,1,n,x,y);} 61 }T; 62 int main(){ 63 read(n),read(q),a[0]=-inf,T.build(1,1,n); 64 for (int i=1;i<=n;i++) read(a[i]); 65 for (int i=1;i<=q;i++) quer[i].init(i); 66 sort(quer+1,quer+q+1,cmp); 67 stack[top=1]=0; 68 for (int i=1,j=1;i<=n;i++){ 69 while (top&&a[stack[top]]>=a[i]) top--; 70 T.cover(stack[top]+1,i,a[i]); 71 for (;quer[j].r==i;j++) ans[quer[j].id]=T.query(quer[j].l,quer[j].r); 72 stack[++top]=i; 73 } 74 for (int i=1;i<=q;i++) printf("%lld\n",ans[i]); 75 return 0; 76 }
第三种:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<cassert> 7 using namespace std; 8 typedef long long int64; 9 char ch; 10 bool ok; 11 void read(int &x){ 12 ok=0; 13 for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 14 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 15 if (ok) x=-x; 16 } 17 const int inf=2147483647; 18 const int maxn=100005; 19 const int maxm=maxn; 20 int n,q,a[maxn],x,y,l[maxn],r[maxn],top,stack[maxn],pos[maxn]; 21 struct Graph{ 22 int tot,now[maxn],son[maxm],pre[maxm]; 23 int64 val[maxm],dis[maxn]; 24 void put(int a,int b,int64 c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;} 25 void dfs(int u){for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) dis[v]=dis[u]+val[p],dfs(v);} 26 }G[2]; 27 int st[maxn][17],sn,bel[maxn]; 28 int64 ans[maxn],res; 29 struct Queries{ 30 int l,r,id; 31 void init(int i){read(l),read(r),id=i;} 32 }queries[maxn]; 33 bool cmp(const Queries &a,const Queries &b){return bel[a.l]<bel[b.l]||(bel[a.l]==bel[b.l]&&bel[a.r]<bel[b.r]);} 34 int get_min(int i,int j){return a[i]<a[j]?i:j;} 35 int calc(int x,int y){ 36 if (x>y) swap(x,y); 37 int step=pos[y-x+1]; 38 return get_min(st[x][step],st[y-(1<<step)+1][step]); 39 } 40 void movel(int x,int y,int op){ 41 int p=calc(x,y); 42 int64 tmp=G[1].dis[x]-G[1].dis[p]+1LL*a[p]*(y-p+1); 43 res+=op*tmp; 44 } 45 void mover(int x,int y,int op){ 46 int p=calc(x,y); 47 int64 tmp=G[0].dis[y]-G[0].dis[p]+1LL*a[p]*(p-x+1); 48 res+=op*tmp; 49 } 50 void work(){ 51 int l=1,r=1; res=a[1]; 52 for (int i=1;i<=q;i++){ 53 for (;r<queries[i].r;r++) mover(l,r+1,1); 54 for (;l>queries[i].l;l--) movel(l-1,r,1); 55 for (;r>queries[i].r;r--) mover(l,r,-1); 56 for (;l<queries[i].l;l++) movel(l,r,-1); 57 ans[queries[i].id]=res; 58 } 59 for (int i=1;i<=q;i++) printf("%lld\n",ans[i]); 60 } 61 int main(){ 62 read(n),read(q),sn=sqrt(n),pos[0]=-1; 63 for (int i=1;i<=n;i++) bel[i]=i/sn; 64 for (int i=1;i<=n;i++) pos[i]=pos[i>>1]+1; 65 for (int i=1;i<=n;i++) read(a[i]); 66 for (int i=1;i<=n;i++) st[i][0]=i; 67 for (int j=1;j<=17;j++) for (int i=1;i<=n;i++){ 68 st[i][j]=st[i][j-1]; 69 if (i+(1<<(j-1))<=n) st[i][j]=get_min(st[i][j],st[i+(1<<(j-1))][j-1]); 70 } 71 a[0]=a[n+1]=-inf; 72 stack[top=1]=0; 73 for (int i=1;i<=n;i++){ 74 while (top&&a[stack[top]]>=a[i]) top--; 75 G[0].put(stack[top],i,1LL*(i-stack[top])*a[i]); 76 stack[++top]=i; 77 } 78 stack[top=1]=n+1; 79 for (int i=n;i>=1;i--){ 80 while (top&&a[stack[top]]>a[i]) top--; 81 G[1].put(stack[top],i,1LL*(stack[top]-i)*a[i]); 82 stack[++top]=i; 83 } 84 G[0].dfs(0),G[1].dfs(n+1); 85 for (int i=1;i<=q;i++) queries[i].init(i); 86 sort(queries+1,queries+q+1,cmp); 87 work(); 88 return 0; 89 }