码迷,mamicode.com
首页 > 编程语言 > 详细

HDU4456-Crowd (坐标旋转处理+hash处理+二维树状数组)

时间:2017-12-04 14:58:57      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:onclick   线性   return   val   原来   树状   两种   结果   abc   

题意:

给出一个矩阵,初始每个位置上的值都为0,然后有两种操作

  •    一种是更改某个位置上的值
  •   另一种是求某个位置附近曼哈顿距离不大于K的所有位置的值的总和

 技巧:

  • 坐标旋转,使得操作之后菱形变成方方正正的矩形,(即“曼哈顿距离”转化为“切比雪夫距离”)方便使用树状数组进行计算。
  • 利用哈希进行离散,节约空间,即不开不必要的空间。

坐标旋转:

  • X=x-y
  • Y=x+y

   技术分享图片技术分享图片

这个结果显示,A’B’C’D’(X,Y)是ABCD(x,y)绕原点(0,0)左旋转45°后的结果,同时长度变为原来的sqrt(2)倍。

由于菱形范围为对角线OA的距离,正方形为一半边长OM的距离,相等,所以无需对距离进行操作。

坐标离散:

 

1,离线离散

技术分享图片
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 4000005;
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] + N;
        int y = X[i] + Y[i];
        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] + N;
        int y = X[i] + Y[i];

        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 () {
    while (scanf("%d", &N) == 1 && N) {
        init();
        solve();
    }
    return 0;
}
View Code

 

2,线性探测再散列。以前再kbrdhash时用到过,大同小异吧http://www.cnblogs.com/hua-dong/p/7714475.html

 

 但是不知道为什么炸内存了(别人的代码)

技术分享图片
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define MAXN 4001003
#define MAXM 88888
using namespace std;
int n, m;
int W;
int h[MAXN];
int a[MAXN];
int hash(int x)
{
    int pos = x % MAXN;
    while(true)
    {
        if(h[pos] == 0 || h[pos] == x)
        {
            h[pos] = x;
            return pos;
        }
        pos++;
        if(pos == MAXN) pos = 0;
    }
}
int gethash(int x)
{
    int pos = x % MAXN;
    while(true)
    {
        if(h[pos] == 0 || h[pos] == x) return pos;
        pos++;
        if(pos == MAXN) pos = 0;
    }
}
inline int lowbit(int x)
{
    return x & -x;
}
void add(int x, int y, int val)
{
    for(int i = x; i <= W; i += lowbit(i))
        for(int j = y; j <= W; j += lowbit(j))
            a[hash(i * W + j)] += val;
}
int getsum(int x, int y)
{
    int sum = 0;
    for(int i = x; i > 0; i -= lowbit(i))
        for(int j = y; j > 0; j -= lowbit(j))
            sum += a[gethash(i * W + j)];
    return sum;
}
int main()
{
    int p, x, y, z, xa, xb, ya, yb, newx, newy;
    while(scanf("%d", &n) != EOF && n)
    {
        scanf("%d", &m);
        W = n * 2;
        memset(a, 0, sizeof(a));
        memset(h, 0, sizeof(h));
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d%d%d", &p, &x, &y, &z);
            newx = x - y + n;
            newy = x + y;
            if(p == 1) add(newx, newy, z);
            else
            {
                xa = max(1, newx - z);
                ya = max(1, newy - z);
                xb = min(W, newx + z);
                yb = min(W, newy + z);
                printf("%d\n", getsum(xb, yb) - getsum(xa - 1, yb) - getsum(xb, ya - 1) + getsum(xa - 1, ya - 1));
            }
        }
    }
    return 0;
}
View Code

 

 

 

(类似用到了坐标转化的题:HDU4312)

HDU4456-Crowd (坐标旋转处理+hash处理+二维树状数组)

标签:onclick   线性   return   val   原来   树状   两种   结果   abc   

原文地址:http://www.cnblogs.com/hua-dong/p/7976753.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!