以前写过一个一维的,今晚用了好久跟据那个一维的改成了二维然后做了这题
ST算法:求指定区间内的最值
一维: 设 d[i][j] 表示[i,i+1,...,i+2^j-1]这个区间内的最值然后给出的任意一个区间都可以用两个这样的区间来表示(有重叠部分)然后只需要对两个区间求一个max就ok
d[i][j]可以通过递推得到
二维:设d[i][j][k][l]表示由[i,i+1,....,i+2^j-1]行和[k,k+1,....,k+2^l-1]列组成的子矩阵内的最大值,然后可以由四部分放一起表示出来,就是这个部分让人想得一死。。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int maxn = 301; 6 int d[maxn][9][maxn][9],a[maxn][maxn]; 7 int n,m; 8 void init() 9 { 10 int sn = 0,sm = 0,x = 1; 11 while((x<<1)<n)x=x<<1,sn++; 12 x = 1; 13 while((x<<1)<m)x=x<<1,sm++; 14 for(int i = 1;i<=n;++i)for(int j = 1;j<=m;++j) 15 d[i][0][j][0] = a[i][j]; 16 for(int i = 0;i<=sn;i++)for(int j = 0;j<=sm;++j) 17 { 18 if(i==0 && j==0)continue; 19 int lenn = (1<<i)-1,lenm = (1<<j)-1; 20 for(int k = 1;k+lenn<=n;++k)for(int l = 1;l+lenm<=m;++l) 21 if(i==0 && j!=0)d[k][0][l][j] = max(d[k][0][l][j-1],d[k][0][l+((lenm+1)>>1)][j-1]); 22 else if(i!=0 && j==0)d[k][i][l][0] = max(d[k][i-1][l][0],d[k+((lenn+1)>>1)][i-1][l][0]); 23 else d[k][i][l][j] = max(d[k][i-1][l][j-1],max(d[k][i-1][l+((lenm+1)>>1)][j-1],max(d[k+(lenn+1)/2][i-1][l][j-1],d[k+(lenn+1)/2][i-1][l+(lenm+1)/2][j-1]))); 24 } 25 } 26 int query(int x,int y,int l,int r) 27 { 28 int lenn = 1,sn = 0,lenm = 1,sm = 0; 29 while(lenn*2<l-x+1)lenn=lenn<<1,sn++; 30 while(lenm*2<r-y+1)lenm=lenm<<1,sm++; 31 return max(d[x][sn][y][sm],max(d[x][sn][r-lenm+1][sm],max(d[l-lenn+1][sn][y][sm],d[l-lenn+1][sn][r-lenm+1][sm]))); 32 } 33 int main() 34 { 35 freopen("in.txt","r",stdin); 36 while(~scanf("%d%d",&n,&m)) 37 { 38 for(int i = 1;i<=n;++i)for(int j = 1;j<=m;++j) 39 scanf("%d",&a[i][j]); 40 init(); 41 int T;scanf("%d",&T); 42 while(T--) 43 { 44 int x,y,l,r; 45 scanf("%d%d%d%d",&x,&y,&l,&r); 46 int ans = query(x,y,l,r); 47 printf("%d ",ans); 48 if(a[x][y]==ans||a[l][r]==ans||a[x][r]==ans||a[l][y]==ans)printf("yes\n"); 49 else printf("no\n"); 50 } 51 } 52 return 0; 53 }
时间: 2024-10-25 16:22:05