1. 程式人生 > >【範圍值】一維二維Sparse Table

【範圍值】一維二維Sparse Table

寫在前面:

  記錄了個人的學習過程,同時方便複習

 

  • Sparse Table

  有些情況,需要反覆讀取某個指定範圍內的值而不需要修改

  逐個判斷區間內的每個值顯然太浪費時間

  我們希望用空間換取時間

  ST表就是為此存在的

 

  在一維二維甚至三維中,利用動態規劃的思想,將區域反覆切割直到不能再分

  每一次切割產生的範圍都可以儲存想要的值:

    在生成時找好獲得值的方法

    查詢時找好獲取值得關係

  在儲存時,由於分割總是分成兩半(橫著來一下,豎著來一下就是四段)

  利用這個性質,就能高效的用2k或者2kn

,2km表示每個分割區域的長度(面積)

  而在實現ST表的功能時,是將以上內容倒著進行的

 

  下面的程式碼僅僅是實現查詢範圍最大值

  若想查詢範圍最小值,對於二維的情況,可能會遇到一個矩陣沒有填滿的情況,取到了0

  這種情況需要特判一下

  同理,範圍最大公因數,最小公倍數也需要特判

  但是最大值,差,和這種有沒有多出來的0都一樣的,就不必特判了

(這一點在二維的矩陣樹裡也有體現)

 

 

  一維Sparse Table,區間類動態規劃

C++:

 1 #include<bits/stdc++.h>
 2 #define
re register 3 4 using namespace std; 5 6 const int MAXN=100010; 7 int n,f[MAXN][31],Ql,Qr; 8 //f[左端點][2^k] 9 //區間[左端點][左端點+2^k-1] 10 11 inline int C_max(int a,int b){return a>b? a:b;} 12 13 int RMQ(int l,int r){ 14 int t=0;//需要一個t使得2^k>=(r-l+1),2^k<(r-l+1),即兩個2^t長度能覆蓋區間 15 while((1
<<(t+1))<=(r-l+1)) t++;//直到2^(t+1)就比總長度還要大了 16 return C_max( 17 f[l ][t], 18 f[r-(1<<t)+1][t] 19 ); 20 } 21 22 int main(int argc,char *argv[],char *enc[]) 23 { 24 scanf("%d",&n); 25 26 for(re int i=1;i<=n;++i) 27 scanf("%d",&f[i][0]); 28 29 for(re int k=1;(1<<k)<=n;++k) 30 for(re int i=1;i+(1<<k)-1<=n;++i) 31 f[i][k]=C_max(//每段長度均為2^(k-1) 32 f[i ][k-1], 33 f[i+(1<<(k-1))][k-1] 34 ); 35 36 while(scanf("%d%d",&Ql,&Qr)==2) 37 printf("%d\n",RMQ(Ql,Qr)); 38 39 return 0; 40 } 41 /* 42 將區間 43 (i,i+2^k-1)分成 44 45 (i,i+2^(k-1)-1) 46 (i+2^(j-1),i+2^k-1) 47 兩部分 48 */

Java:

 1 import java.io.*;
 2 import java.util.*;
 3 
 4 class pony{
 5 
 6     static int MAXN=100010;
 7     static int n,Ql,Qr;
 8     static int[][] f=new int[MAXN][31];
 9     //f[左端點][2^k]
10     //區間[左端點][左端點+2^k-1] 
11 
12     static int C_max(int a,int b){return a>b? a:b;}
13 
14     static int RMQ(int l,int r){
15         int t=0;//需要一個t使得2^k>=(r-l+1),2^k<(r-l+1),即兩個2^t長度能覆蓋區間 
16         while((1<<(t+1))<=(r-l+1)) t++;//直到2^(t+1)就比總長度還要大了
17         return C_max(
18                 f[l         ][t],
19                 f[r-(1<<t)+1][t]
20             );
21     }
22 
23     public static void main(String[] args) throws Exception {
24         
25         Scanner cin=new Scanner(System.in);
26         n=cin.nextInt();
27     
28         for(int i=1;i<=n;++i)
29             f[i][0]=cin.nextInt();
30     
31         for(int k=1;(1<<k)<=n;++k)
32             for(int i=1;i+(1<<k)-1<=n;++i)
33                 f[i][k]=C_max(//每段長度均為2^(k-1)
34                     f[i           ][k-1],
35                     f[i+(1<<(k-1))][k-1]
36                 );
37 
38         Ql=cin.nextInt();
39         Qr=cin.nextInt();
40 
41         System.out.println(RMQ(Ql,Qr));
42     }
43 }

 

  二維Sparse Table,矩陣類動態規劃

C++:

 1 #include<bits/stdc++.h>
 2 #define re register
 3 
 4 using namespace std;
 5 
 6 const int MAXN=1010,MAXM=1010;
 7 int n,m,f[MAXN][MAXN][15][15],qx1,qy1,qx2,qy2;
 8 //f[y1][x1][km][kn]
 9 //矩陣(x1,y1)(x1+2^kn-1,y1+2^km-1)
10 
11 inline int C_max(int a,int b){return a>b? a:b;}
12 int C_max4(int a,int b,int c,int d){return C_max(C_max(C_max(a,b),c),d);}
13 
14 int RMQ(int x1,int y1,int x2,int y2){
15     int tm=0,tn=0;
16     while((1<<(tm+1))<=(y2-y1+1)) ++tm; 
17     while((1<<(tn+1))<=(x2-x1+1)) ++tn;
18     return C_max4(
19                 f[y1          ][x1          ][tm][tn],
20                 f[y2-(1<<tm)+1][x1          ][tm][tn],
21                 f[y1          ][x2-(1<<tn)+1][tm][tn],
22                 f[y2-(1<<tm)+1][x2-(1<<tn)+1][tm][tn]
23             );
24 }
25 
26 int main(int argc,char *argv[],char *enc[])
27 {
28     scanf("%d%d",&n,&m);
29     
30     for(re int i=1;i<=m;++i)
31         for(re int j=1;j<=n;++j)
32             scanf("%d",&f[i][j][0][0]);
33     
34     /*
35         當某一維長度為1時不好處理,單獨拿出來處理 
36     */ 
37     
38     for(re int km=1;(1<<km)<=m;++km)
39         for(int i=1;i+(1<<km)-1<=m;++i)
40             for(int j=1;j<=n;++j)
41                 f[i][j][km][0]=C_max(f[i][j][km-1][0],f[i+(1<<(km-1))][j][km-1][0]);
42                 
43     for(re int kn=1;(1<<kn)<=n;++kn)
44         for(int i=1;i<=m;++i)
45             for(int j=1;j+(1<<kn)-1<=n;++j)
46                 f[i][j][0][kn]=C_max(f[i][j][0][kn-1],f[i][j+(1<<(kn-1))][0][kn-1]);
47     
48     for(re int km=1;(1<<km)<=m;++km)
49         for(re int kn=1;(1<<kn)<=n;++kn)
50             for(re int i=1;i+(1<<km)-1<=m;++i)
51                 for(re int j=1;j+(1<<kn)-1<=n;++j)
52                     f[i][j][km][kn]=C_max4(//每次平分矩形,小矩形長度為2^(j-1),高為2^(i-1)
53                         f[i            ][j            ][km-1][kn-1],
54                         f[i+(1<<(km-1))][j            ][km-1][kn-1],
55                         f[i            ][j+(1<<(kn-1))][km-1][kn-1],
56                         f[i+(1<<(km-1))][j+(1<<(kn-1))][km-1][kn-1]
57                     );
58     
59     while(scanf("%d%d%d%d",&qx1,&qy1,&qx2,&qy2)==4)
60         printf("%d\n",RMQ(qx1,qy1,qx2,qy2));
61     
62     return 0;
63 }
64 /*
65     將矩陣
66         (j        ,i          ,j+2^k-1    ,i+2^k-1    )分成
67         
68         (j        ,i          ,j+2^(k-1)-1,i+2^(k-1)-1)
69         (j        ,i+2^(k-1)-1,j+2^(k-1)-1,i+2^k-1    )
70         (j+2^(k-1),i          ,j+2^k-1    ,i+2^(k-1)-1)
71         (j+2^(k-1),i+2^(k-1)-1,j+2^k-1    ,i+2^k-1    )
72     四部分
73 */

Java:

 1 import java.io.*;
 2 import java.util.*;
 3 
 4 class pony{
 5 
 6     static int MAXN=1010,MAXM=1010;
 7     static int n,m,qx1,qy1,qx2,qy2;
 8     static int[][][][] f=new int[MAXN][MAXN][15][15];
 9     //f[y1][x1][km][kn]
10     //矩陣(x1,y1)(x1+2^kn-1,y1+2^km-1)
11 
12     static int C_max(int a,int b){return a>b? a:b;}
13     static int C_max4(int a,int b,int c,int d){return C_max(C_max(C_max(a,b),c),d);}
14 
15     static int RMQ(int x1,int y1,int x2,int y2){
16         int tm=0,tn=0;
17         while((1<<(tm+1))<=(y2-y1+1)) ++tm; 
18         while((1<<(tn+1))<=(x2-x1+1)) ++tn;
19         return C_max4(
20                 f[y1          ][x1          ][tm][tn],
21                 f[y2-(1<<tm)+1][x1          ][tm][tn],
22                 f[y1          ][x2-(1<<tn)+1][tm][tn],
23                 f[y2-(1<<tm)+1][x2-(1<<tn)+1][tm][tn]
24             );
25     }
26 
27     public static void main(String[] args) throws Exception {
28         
29         Scanner cin=new Scanner(System.in);
30         n=cin.nextInt();
31         m=cin.nextInt();
32     
33         for(int i=1;i<=m;++i)
34             for(int j=1;j<=n;++j)
35                 f[i][j][0][0]=cin.nextInt();
36     
37     /*
38         當某一維長度為1時不好處理,單獨拿出來處理 
39     */ 
40     
41         for(int km=1;(1<<km)<=m;++km)
42             for(int i=1;i+(1<<km)-1<=m;++i)
43                 for(int j=1;j<=n;++j)
44                     f[i][j][km][0]=C_max(f[i][j][km-1][0],f[i+(1<<(km-1))][j][km-1][0]);
45                 
46         for(int kn=1;(1<<kn)<=n;++kn)
47             for(int i=1;i<=m;++i)
48                 for(int j=1;j+(1<<kn)-1<=n;++j)
49                     f[i][j][0][kn]=C_max(f[i][j][0][kn-1],f[i][j+(1<<(kn-1))][0][kn-1]);
50     
51         for(int km=1;(1<<km)<=m;++km)
52             for(int kn=1;(1<<kn)<=n;++kn)
53                 for(int i=1;i+(1<<km)-1<=m;++i)
54                     for(int j=1;j+(1<<kn)-1<=n;++j)
55                         f[i][j][km][kn]=C_max4(//每次平分矩形,小矩形長度為2^(j-1),高為2^(i-1)
56                           f[i            ][j            ][km-1][kn-1],
57                           f[i+(1<<(km-1))][j            ][km-1][kn-1],
58                           f[i            ][j+(1<<(kn-1))][km-1][kn-1],
59                           f[i+(1<<(km-1))][j+(1<<(kn-1))][km-1][kn-1]
60                       );
61     
62         qx1=cin.nextInt();
63         qy1=cin.nextInt();
64         qx2=cin.nextInt();
65         qy2=cin.nextInt();
66 
67         System.out.println(RMQ(qx1,qy1,qx2,qy2));
68     }
69 }