1. 程式人生 > >HDU4456-Crowd (坐標旋轉處理+hash處理+二維樹狀數組)

HDU4456-Crowd (坐標旋轉處理+hash處理+二維樹狀數組)

font http alt show isp 2-2 else shp com

題意:

給出一個矩陣,初始每個位置上的值都為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處理+二維樹狀數組)