HDU 4721 Food and Productivity (二分+树状数组)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题意 :给出n * m的格子,每个格子有两个属性food , prod。对于每一个查询A,B,可以选择某个格子将food属性+A,prod+B,然后以这个格子为中心的正方形两个属性和的最小值最大。

http://acm.hdu.edu.cn/showproblem.php?pid=4721

其实很简单的题, 很早就会了,WA了好多天,结果是一个乘号打成了加号。。。不能更逗

由于所有属性值为正,所以没必要取边界上不完整的正方形,不过处理下也没事。。。

正方形的连长为2 * r + 1,预处理一下子矩阵和。

将所有的正方形两个属性和提取出来,离散化一下food,用BIT维护prod属性的前缀最大值。

对于每一次查询,二分答案ans , 两个属性和都要大于等于ans。

二分下food,查询一下prod的最值。

逆序后维护前缀最大值。。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#define lson step << 1
#define rson step << 1 | 1
#define lowbit(x) (x & (-x))
#define Key_value ch[ch[root][1]][0] 
using namespace std;
typedef long long LL;
const int N = 505;
int n , m , r , q;
int food[N][N] , prod[N][N];
int a[N * N] , b[N * N] , tot , x[N * N];
int s[N * N] , cnt;
void add (int x , int v) {
    for (int i = x ; i <= cnt ; i += lowbit (i)) {
        s[i] = max (s[i] , v);
    }
}
int ask (int x) {
    int ret = 0;
    for (int i = x ; i > 0 ; i -= lowbit (i)) {
        ret = max (ret , s[i]);
    }
    return ret;
}
int main () {
    #ifndef ONLINE_JUDGE
        freopen ("input.txt" , "r" , stdin);
        // freopen ("output.txt" , "w" , stdout);
    #endif
    int t , cas = 0;
    scanf ("%d" , &t);
    while (t --) {
        memset (food , 0 , sizeof(food));
        memset (prod , 0 , sizeof(prod));
        memset (s , 0 , sizeof(s));
        scanf ("%d %d %d %d" , &n , &m , &r , &q);
        for (int i = 1 ; i <= n ; i ++) {
            for (int j = 1 ; j <= m ; j ++) {
                scanf ("%d" , &food[i][j]);
                food[i][j] += food[i - 1][j] + food[i][j - 1] - food[i - 1][j - 1];
            }
        }
        for (int i = 1 ; i <= n ; i ++) {
            for (int j = 1 ; j <= m ; j ++) {
                scanf ("%d" , &prod[i][j]);
                prod[i][j] += prod[i - 1][j] + prod[i][j - 1] - prod[i - 1][j - 1];
            }
        }
        tot = 0;
        r = 2 * r + 1;
        for (int i = r ; i <= n ; i ++) {
            for (int j = r ; j <= m ; j ++) {
                a[tot] = food[i][j] - food[i][j - r] - food[i - r][j] + food[i - r][j - r];
                b[tot] = prod[i][j] - prod[i][j - r] - prod[i - r][j] + prod[i - r][j - r];
                x[tot] = a[tot];
                tot ++;
            }
        }
        sort (x , x + tot);
        cnt = unique (x , x + tot) - x;
        for (int i = 0 ; i < tot ; i ++) {
            int y = cnt - (lower_bound (x , x + cnt , a[i]) - x);
            add (y , b[i]);
        }
        printf ("Case #%d:\n" , ++ cas);
        while (q --) {
            int A , B;
            scanf ("%d %d" , &A , &B);
            int low = min (A , B) + r * r * 1 , high = min (A , B) + r * r * 3 , mid , ans;
            while (low <= high) {
                mid = (low + high) >> 1;
                int y = cnt - (lower_bound (x , x + cnt , mid - A) - x);
                if (y < 1) {
                    high = mid - 1;
                    continue;
                }
                int tmp = ask (y);
                if (tmp + B >= mid) {
                    ans = mid;
                    low = mid + 1;
                }
                else high = mid - 1;
            }
            printf ("%d\n" , ans);
        }
        if (t) puts ("");
    }
    return 0;
}       



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值