zoukankan      html  css  js  c++  java
  • HDU4456-Crowd(坐标旋转+二位树状数组+离散化)

    转自:http://blog.csdn.net/sdj222555/article/details/10828607

    大意就是给出一个矩阵

    初始每个位置上的值都为0

    然后有两种操作

    一种是更改某个位置上的值

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

    然后这里用了一个非常牛叉的技巧

    将所有点绕原点左旋45°

    然后新的坐标也很好计算

    x' = (x - y) * sqrt(2) / 2

    y' = (x + y) * sqrt(2) / 2

    由于都是小数

    所以乘个sqrt(2) 就成整数了

    x' = (x - y) 

    y' = x + y

    由于x- y可能是负数。所以把点都右移一下  x' = x + y + n (n是矩阵宽度)然后矩阵的宽度和长度也就各自扩大了一倍

    然后我们就可以惊奇的发现

    原先是求 abs(x - x0) + abs(y - y0) <= k 的所有位置的值的和

    现在变成了 abs(x' - x0') <= k 或者abs(y' - y0') <= k 就可以了

    也就变成了求一个子矩阵的和

    然后就可以欢快的用二维树状数组来解了

    但是发现题目给的范围比较大

    1W*1W的矩阵

    但是询问的话 有8W

    那么我们可以就把所有询问中树状数组操作过程中用到的点给离散出来。

    然后就可以节省内存了

    离散的话可以有两种方法

    一种是线性探测再散列

    这个可以在线处理询问

    另一个就是先把所有可能用到的都取出来,然后先都离散了,离线处理询问

    离散之后,每个x,y都应该对应一个唯一的数。我们就可以用一个一维的数组,来完成这个二维树状数组的功能

    首先是先把询问存起来的离散方式

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <cstdio>
    
    using namespace std;
    
    const int N = 10005;
    const int M = 80005;
    
    int W;  // 坐标转换后的边长
    int h[M*40], cnt;
    int bit[M*40];
    int op[M], x[M], y[M], v[M];
    
    int lowbit(int x) {
        return x&-x;
    }
    void ready(int x, int y) {
        for (int i = x; i <= W; i += lowbit(i)) {
            for (int j = y; j <= W; j += lowbit(j)) {
                h[cnt++] = i*W+j;
            }
        }
    }
    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)) {
                int pos = lower_bound(h, h+cnt, i*W+j) - h;
                bit[pos] += 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)) {
                int pos = lower_bound(h, h+cnt, i*W+j) - h;
                if (h[pos] == i*W+j) sum += bit[pos]; // 没处理过的数是0 不用考虑
            }
        }
        return sum;
    }
    
    int main()
    {
        int n, m;
        while (~scanf("%d", &n) && n) {
            scanf("%d", &m);
            W = n*2;
            cnt = 0;
            memset(bit, 0, sizeof bit);
            int tx, ty;
            for (int i = 0; i < m; ++i) {
                scanf("%d%d%d%d", &op[i], &tx, &ty, &v[i]);
                x[i] = tx - ty + n;
                y[i] = tx + ty;
                if (op[i] == 1) { // 1 means update, 2 means query
                    ready(x[i], y[i]);
                }
            }
            sort(h, h+cnt);
            cnt = unique(h, h+cnt) - h;
            for (int i = 0; i < m; ++i) {
                if (op[i] == 1) {
                    add(x[i], y[i], v[i]);
                } else {
                    int L = max(1, x[i]-v[i]);
                    int B = max(1, y[i]-v[i]);
                    int R = min(W, x[i]+v[i]);
                    int T = min(W, y[i]+v[i]);
                    printf("%d
    ", getsum(R,T) - getsum(L-1,T)-getsum(R,B-1)+getsum(L-1,B-1));
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    23种设计模式总篇
    23种设计模式之抽象工厂
    23种设计模式之原型模式
    23种设计模式之适配器模式
    23种设计模式之工厂模式
    23种设计模式之模板方法
    Cloudera Manager 5和CDH5离线安装
    ArrayList vs. LinkedList vs. Vector
    在Java中怎样把数组转换为ArrayList?
    两个有序数组的中位数 【算法】
  • 原文地址:https://www.cnblogs.com/wenruo/p/5955564.html
Copyright © 2011-2022 走看看