:より転載https://lornd.top/index.php/archives/25/
二次元の点の数(フェンウィックツリー)演習。
トピックリンク:P2163 SHOI2007の庭師のトラブル
効果の対象に
所与の平面矩形システム座標\(N- \)でポイントを\(Mの\)時間は、ポイントの数を(側面を含む)長方形の内部に依頼するたびに尋ねました。
\(N、M \ル。5 \ ^。5回10 \) 、点の水平および垂直座標(\ 0 \ルX_I、Y_I \ル。7 10 ^ \) 、各矩形の左下頂点与える\((a_iをはB_i)\)と右上の頂点\((C_I、D_I)\) 。
問題解決のためのアイデア
我々は、頂点を見つけることができる場合(\)(X_I、Y_I \の ) 点左下の数\(F((X_I、Y_I))\) 、次いで、矩形のプレフィックスと考えに記載の(\((a_iをを、B_i)、(C_I、D_I))\) :明確である:\ [ANS = F((C_I、D_I)) - F((a_iを- 1、D_I)) - F((C_I、B_i -1)。 )+ F((a_iを- 1 、b_i - 1))\]
だから我々は、問題のポイント数(左下のポイントを求める問題に変換されるポイント数の2次元問題を)、それに対処する方法を検討してください。
ポイント番号2次元問題
我々は、対応する抽象化のポイントへのお問い合わせは、プラス座標系の任意の原点を置き、それらを一緒に保つために、オフラインで考える(X \)\軸最初のキーとして、\(Y \)軸を第二ソートキーの座標、その後、左から右にハンドルをすべての点、我々は唯一の問い合わせの数に委ねたびに指し示すことができることを確実にするようになっています。
ため\(Y \)軸、我々は、ツリーアレイ構築\(ビット[I] \) 、元の配列である\([I] \) 、現在垂直考慮にすべてのポイントを表します以下の座標は\(私は\)ポイントの数です。
あなたは、座標系の任意の原点が発生した場合ようにポイントを扱うには、、、オペレーティング・フェンウィックツリーを変更することが考えられる\([I] \)に遭遇尋ねるのポイント場合、クエリは同等です。プラスワンは、\([1 \ SIM I ] \) と。
フェンウィックツリー元の配列の定義以来、私たちは単純にお問い合わせの数を下回る指すことになり、私たちは続くので\(のx \)を軸方向を処理するために、我々は唯一の左の点にポイントを依頼するカウントされますので、我々結果は、クエリの左下の点の点の数です。
戻る元の質問に、私たちは今のすべてのポイントを見つける\(F((X_I、Y_I ))\) 値を、しかし、鍵が4点に対応する四角形、各ポイントであるとき、最終的な答えを算出した結果加減算の場合、異なる、矩形よりは、どのように我々はこれを防ぐか混乱しましたか?
まず、我々は、属性ごとにポイントを追加することができる\(IDが\)解像度を容易にするために、第一矩形に属する点の数を表し、我々缶座標系の原点\(ID \)割り当て\(0 \) 、我々は、各点が長方形の最大値に対応することを保証することができるようになっています。
第二に、加算と減算の問題に、最終的な答えはマイナスを追加することです計算する際に、我々はそれを知っていない時点で見えますが、我々はそれが長方形に置か見たとき、我々は見つけることができ、矩形の左下隅と右上隅を頂点がプラス、マイナス、他のポイントは、我々は各点の属性を追加することができ、\(フラグ= \ 1 \午後 ) のみ何の頭脳を必要としない、我々は、単一のクエリに対する答えを扱うときように、加算と減算を決定するために、プラスそれは、もちろん、で乗算することができます\(フラグ\) 。
このように、我々は、矩形の各ポイントの数を取得することができます。
私たちは、縦軸上に構築されて構築フェンウィックツリー、添字の範囲はどのように行う、データが大きすぎる、範囲の縦軸に対応しています。しかし、問題ありますか?縦軸は、直接こと離散!
次のように最終的なコードです。
#include <cstdio>
#include <algorithm>
const int MAXN = 5e5 + 1;
int n, m, a, b, c, d, cnt;
int res[MAXN * 5];
int BIT[MAXN * 5];
int ans[MAXN];
struct node {
int num, place;
node(int nn = 0, int pp = 0) {
num = nn;
place = pp;
}
bool operator < (const node &another) const {
return num < another.num;
}
}temp[MAXN * 5];
struct point {
int x, y, id, flag;
point (int xx = 0, int yy = 0, int ii = 0, int ff = 0) {
x = xx;
y = yy;
id = ii;
flag = ff;
}
bool operator < (const point another) const {
if (x == another.x){
if (y == another.y)
return id < another.id;
else
return y < another.y;
}
else
return x < another.x;
}
}arr[MAXN * 5];
void discretizate() {
std::sort(temp + 1, temp + cnt + 1);
int cur = 1;
for (int i = 1; i <= cnt; ++i) {
res[temp[i].place] = cur;
if (temp[i].num != temp[i + 1].num)
++cur;
}
for (int i = 1; i <= cnt; ++i) {
arr[i].y = res[i];
}
}
int lowbit(int key) {
return key & (-key);
}
void modify(int place, int key) {
for (; place <= n; place += lowbit(place)) {
BIT[place] += key;
}
}
int query(int place) {
int tmp = 0;
for (; place; place -= lowbit(place)) {
tmp += BIT[place];
}
return tmp;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &a, &b);
arr[++cnt] = point(a, b);
temp[cnt] = node(b, cnt);
}
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d%d", &a, &b, &c, &d); //将一个矩形抽象成四个点加入序列
arr[++cnt] = point(a - 1, b - 1, i, 1);
temp[cnt] = node(b - 1, cnt);
arr[++cnt] = point(a - 1, d, i, -1);
temp[cnt] = node(d, cnt);
arr[++cnt] = point(c, b - 1, i, -1);
temp[cnt] = node(b - 1, cnt);
arr[++cnt] = point(c, d, i, 1);
temp[cnt] = node(d, cnt);
}
discretizate(); //离散化
std::sort(arr + 1, arr + cnt + 1);
for (int i = 1; i <= cnt; ++i) {
if (arr[i].id == 0)
modify(arr[i].y, 1);
else
ans[arr[i].id] += arr[i].flag * query(arr[i].y);
}
for (int i = 1; i <= m; ++i) {
printf("%d\n", ans[i]);
}
return 0;
}