HDU4456-Crowd (坐標旋轉處理+hash處理+二維樹狀數組)
阿新 • • 發佈:2017-12-04
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]; intView CodeO[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; } } voidadd(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; }
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處理+二維樹狀數組)