大致題意
有n堵水平於座標軸的牆,以及m只小鳥,小鳥一定會朝離自己最近的牆飛去撞暈自己,且只能飛向平行於座標軸的 4個方向,撞到牆的邊緣也算合理衝撞(即是說可以往延長線飛)。求各堵牆上各撞了幾隻小鳥。n, m <= 50000。 題解
用線段樹維護牆的索引值,對應於小鳥的4個方向,分別在x, y軸上正向和反向掃瞄,更新離小鳥最近的牆。
掃瞄線法,即對於某乙個方向按座標值順序掃瞄。因為此處可在延長線上飛,若對x軸掃瞄,對於牆兩個端點y座標值相等(即考慮延長線)和y座標值不等都對線段樹進行更新。
題中沒有給出座標值範圍,考慮到線段樹的維護,要先座標離散化。本來用vector的erase(), unique()來做離散化,但這裡需要保留原值計算最小距離,還要考慮到x, y的對應關係,碼量略大。然後發現了手動座標離散化的方法:按照座標值對索引做排序,然後可以得到保留原順序的離散座標。用索引做,離散值、原值以及x, y直接對應,妙啊。
對於牆而言,成對輸入的座標,若儲存在相鄰位置,可以通過索引異或1方便的求出另乙個座標值。
#include
#include
#include
#include
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define abs(x) ((x) < 0 ? -(x) : (x))
#define inf 0x3f3f3f3f
#define eps 1e-4
#define m_pi 3.14159265358979323846
#define max_a 150015
#define max_m 50005
#define max_n 50005
using
namespace std;
int n, m, ax_size, w_size;
int x[max_a]
, y[max_a]
;int sx[max_a]
, sy[max_a]
, rx[max_a]
, ry[max_a]
;//座標離散化
int* t;
bool
cmp(
int x,
int y)
void
compress
(int
* x,
int* sx,
int* rx)
}void
init()
const
int st_size =(1
<<19)
-1;int wall[st_size]
;int chs[max_m]
, dis[max_m]
, cnt[max_n]
;//牆的索引線段樹
void
update
(int a,
int b,
int id,
int k,
int l,
int r)
update
(a, b, id, chl, l, m)
;update
(a, b, id, chr, m, r);}
}int
query
(int a,
int b,
int k,
int l,
int r)
}void
line_sweep
(int
* sy,
int* x,
int h,
int i)
}else}}
}void
sweep
(int
* sy,
int* rx,
int* x,
int h)
void
solve()
intmain()
return0;
}
POJ3470 Walls(線段樹)(掃瞄線)
本義 有n堵牆,m只智障鳥,給出牆端點座標,鳥座標,牆一定是平行於座標軸,橫著或豎著,每只鳥都會選乙個離自己最近的牆撞過去,鳥一定是平行於座標軸飛行,只能橫著或豎著飛,問每堵牆被幾隻鳥撞過。題目沒說的坑爹問題 include include include using namespace std c...
POJ 1151 線段樹 掃瞄線
cf上遇到一題掃瞄線,二話不說立刻補。該類題目計算座標中邊平行於x,y軸的矩形的覆蓋面積。這樣可以通過離散化x座標,然後建立區間,通過線段樹管理。然後每條掃瞄線更新區間覆蓋和計算面積。對於上面的矩形就有4條掃瞄線,有3個區間。第一條掃瞄線覆蓋1,2區間。第二條掃瞄線覆蓋2,3區間。第三條掃瞄線是第乙...
POJ1389 掃瞄線 線段樹
一道經典的掃瞄線 線段樹求矩形面積並的題目 用線段樹維護y,記錄所有線段被覆蓋的次數和長度,掃瞄線維護x,把乙個長方形拆成兩個事件,左邊界作為 1,右邊界作為 1,即可利用線段樹進行維護。非離散化版本 include includeusing namespace std define lson k ...