【範圍值】一維二維Sparse Table
阿新 • • 發佈:2018-12-22
寫在前面:
記錄了個人的學習過程,同時方便複習
- Sparse Table
有些情況,需要反覆讀取某個指定範圍內的值而不需要修改
逐個判斷區間內的每個值顯然太浪費時間
我們希望用空間換取時間
ST表就是為此存在的
在一維二維甚至三維中,利用動態規劃的思想,將區域反覆切割直到不能再分
每一次切割產生的範圍都可以儲存想要的值:
在生成時找好獲得值的方法
查詢時找好獲取值得關係
在儲存時,由於分割總是分成兩半(橫著來一下,豎著來一下就是四段)
利用這個性質,就能高效的用2k或者2kn ,2km表示每個分割區域的長度(面積)
而在實現ST表的功能時,是將以上內容倒著進行的
下面的程式碼僅僅是實現查詢範圍最大值
若想查詢範圍最小值,對於二維的情況,可能會遇到一個矩陣沒有填滿的情況,取到了0
這種情況需要特判一下
同理,範圍最大公因數,最小公倍數也需要特判
但是最大值,差,和這種有沒有多出來的0都一樣的,就不必特判了
(這一點在二維的矩陣樹裡也有體現)
一維Sparse Table,區間類動態規劃
C++:
1 #include<bits/stdc++.h> 2 #definere 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 }