二维 ST POJ 2019

题目大意:给你一个n*n的矩阵,每次给你一个点(x,y),以其为左上角,宽度为b的矩阵中最小的数值和最大数值的差是多少?  一共k个询问。

思路:简单的二维st。

定义dp(i,j,k,L)表示以(i,j)为左上角,宽度为(2^k, 2^L)的区间内的最大(小)值。

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<algorithm>
#include<iostream>
#include<utility>
#include<stdlib.h>
#include<time.h>
#include<cmath>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 250 + 5;
int dp[maxn][maxn][8][8], dp2[maxn][maxn][8][8];
int n, b, k;

void init_st(){
    for (int i = 0; (1 << i) <= n; i++){
        for (int j = 0; (1 << j) <= n; j++){
            if (i == 0 && j == 0) continue;
            for (int x = 1; x + (1 << i) - 1 <= n; x++){
                for (int y = 1; y + (1 << j) - 1 <= n; y++){
                    if (i == 0) {
                        dp[x][y][i][j] = min(dp[x][y][i][j - 1], dp[x][y + (1 << (j - 1))][i][j - 1]);
                        dp2[x][y][i][j] = max(dp2[x][y][i][j - 1], dp2[x][y + (1 << (j - 1))][i][j - 1]);
                    }
                    else {
                        dp[x][y][i][j] = min(dp[x][y][i - 1][j], dp[x + (1 << (i - 1))][y][i - 1][j]);
                        dp2[x][y][i][j] = max(dp2[x][y][i - 1][j], dp2[x + (1 << (i - 1))][y][i - 1][j]);
                    }
                }
            }
        }
    }
}

int query(int x, int y, int X, int Y){
    int maxi = 0, mini = 1e8;
    int k1 = 0, k2 = 0;
    while (1 << (1 + k1) <= X - x) k1++;
    while (1 << (1 + k2) <= Y - y) k2++;
    maxi = max(maxi, max(dp2[x][y][k1][k2], dp2[X - (1 << k1) + 1][y][k1][k2]));
    maxi = max(maxi, max(dp2[x][Y - (1 << k2) + 1][k1][k2], dp2[X - (1 << k1) + 1][Y - (1 << k2) + 1][k1][k2]));

    mini = min(mini, min(dp[x][y][k1][k2], dp[X - (1 << k1) + 1][y][k1][k2]));
    mini = min(mini, min(dp[x][Y - (1 << k2) + 1][k1][k2], dp[X - (1 << k1) + 1][Y - (1 << k2) + 1][k1][k2]));
    //printf("maxi = %d mini = %d\n", maxi, mini);
    return maxi - mini;
}

int main(){
    //while (true){
    cin >> n >> b >> k;
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= n; j++){
            scanf("%d", &dp[i][j][0][0]);
            dp2[i][j][0][0] = dp[i][j][0][0];
        }
    }
    init_st();
    for (int i = 1; i <= k; i++){
        int x, y; scanf("%d%d", &x, &y);
        int ans = query(x, y, x + b - 1, y + b - 1);
        printf("%d\n", ans);
    }
    //}
    return 0;
}
View Code

 

posted @ 2016-11-26 22:03  知る奇迹に  阅读(312)  评论(0编辑  收藏  举报