题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4456

题目:


N*N的网格,M个询问

p=2时输出到(x,y)的曼哈顿距离小于等于z的点对应的值之和

 

解题思路:


(1)到A(x,y)的曼哈顿距离小于等于z的点分布在以A为中心,中垂线的一半=z的菱形上(菱形的四个边都相同),把曼哈顿忽略转化为切比雪夫距离,到A(x,y)的曼哈顿距离小于等于z的点分布在以A'(A'为转为后的坐标)为中心,边长2*z的正方形内:(x,y) --->(x+y, x-y+N),且转换后的网格相当于原来的4倍左右,但其实需要离散的点并没有那么多,网上的题解都是取了400万

(2)找到这个正方形的左上角和右下角并计算这个区间内的点的值的和(二维树状数组解决),相当于二维树状数组的单点更新和区间查询,注意不要越界

(3)N最大为100000,点太多了,需要离散化,并且只离散化有用的点,先对M个询问给出的所有的点进行离散化,并且按照二维树状数组的方式进行离散化,因为只有用二维树状数组更新和求sum值的那些点才有用,才需要离散化

12年杭州区域赛的金牌题好像是,@(・●・)@溜了溜了

 

ac代码:


#include <bits/stdc++.h>

using namespace std;
const int maxn = 4000005;//神奇的400万,可能数据很水,而且好像也离散不出来那么多数
const int maxm = 80005;

#define lowbit(x) ((x)&(-x))
int N, M, W, E, H[maxn+5], fenw[maxn + 5];
int O[maxm], X[maxm], Y[maxm], Z[maxm];

inline int find (int x) {
    return lower_bound(H + 1, H + E, x) - H;
}

void hashPoint (int x, int y)
{
    for (int i = x; i <= W; i += lowbit(i))
    {
        for (int j = y; j <= W; j += lowbit(j))
            H[E++] = i * W + j;
    }
}

void add(int x, int y, int d)
{
    for (int i = x; i <= W; i += lowbit(i))
    {
        for (int j = y; j <= W; j += lowbit(j))
        {
            int pos = find(i * W + j);
            fenw[pos] += d;
        }
    }
}

int sum (int x, int y)
{
    int ret = 0;
    for (int i = x; i; i -= lowbit(i))
    {
        for (int j = y; j; j -= lowbit(j))
        {
            int pos = find(i * W + j);
            if (H[pos] == i * W + j) //可能没有找到这个值
                ret += fenw[pos];
        }
    }
    return ret;
}

void init ()
{
    E = 1;
    W = 2 * N;
    scanf("%d", &M);
    memset(fenw, 0, sizeof(fenw));

    for (int i = 1; i <= M; i++)
    {
        scanf("%d%d%d%d", &O[i], &X[i], &Y[i], &Z[i]);
        int x = X[i] + Y[i];
        int y = X[i] - Y[i] + N;
        if (O[i] == 1)
            hashPoint(x, y);
    }
    sort(H + 1, H + E);
    E = unique(H + 1, H + E) - H;
}

void solve() {
    for (int i = 1; i <= M; i++)
    {
        int x = X[i] + Y[i];
        int y = X[i] - Y[i] + N;

        if (O[i] == 1)
            add(x, y, Z[i]);
        else
            {
            int a = max(1, x - Z[i]);
            int b = max(1, y - Z[i]);
            int c = min(W, x + Z[i]);
            int d = min(W, y + Z[i]);
            printf("%d\n", sum(c, d) - sum(c, b-1) - sum(a-1, d) + sum(a-1, b-1));
        }
    }
}

int main ()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    while (scanf("%d", &N) == 1 && N)
    {
        init();
        solve();
    }
    return 0;
}