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

Sample Output

28
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 }

 

posted @ 2016-04-22 21:58  chenyushuo  阅读(1020)  评论(0编辑  收藏  举报