觀察者在原點,奶牛直線運動。奶牛間有遮擋關係(距離較近者遮擋較遠者)。求最終可見奶牛數。N ≤ 100,000。
每頭奶牛運動軌跡投影到角度域,形成一個時間區間 [st, ed],期間該角度被該奶牛佔用。
按距離原點遠近(y 座標)從遠到近處理:遠處奶牛先「塗色」其時間區間,近處奶牛後塗色會覆蓋遠處。
最終線段樹中顏色出現過的奶牛即為可見。
st, ed,排序去重,映射到 1..Kpushdown 將父節點顏色傳給子節點#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
struct Cow {
int x, y, c; // 位置、速度
int st, ed; // 時間區間
bool operator<(const Cow& o) const { return y > o.y; } // 遠到近
void read() {
scanf("%d%d%d", &x, &y, &c);
x = -x; // 統一朝向
st = c * (x - 1);
ed = st + c;
}
} cows[MAXN];
pair events[MAXN * 2];
int tree[MAXN * 4];
bool visible[MAXN];
void pushdown(int rt) {
if (tree[rt]) {
tree[rt<<1] = tree[rt];
tree[rt<<1|1] = tree[rt];
tree[rt] = 0;
}
}
void update(int l, int r, int L, int R, int c, int rt) {
if (l == L && r == R) { tree[rt] = c; return; }
pushdown(rt);
int mid = (l + r) >> 1;
if (R <= mid) update(l, mid, L, R, c, rt<<1);
else if (L > mid) update(mid+1, r, L, R, c, rt<<1|1);
else {
update(l, mid, L, mid, c, rt<<1);
update(mid+1, r, mid+1, R, c, rt<<1|1);
}
}
int query(int l, int r, int pos, int rt) {
if (l == r) return tree[rt];
pushdown(rt);
int mid = (l + r) >> 1;
return (pos <= mid) ? query(l, mid, pos, rt<<1) : query(mid+1, r, pos, rt<<1|1);
}
int main() {
int n; cin >> n;
for (int i = 1; i <= n; i++) cows[i].read();
sort(cows + 1, cows + n + 1);
// 離散化時間點
int cnt = 0;
for (int i = 1; i <= n; i++) {
events[++cnt] = {cows[i].st, &cows[i].st};
events[++cnt] = {cows[i].ed, &cows[i].ed};
}
sort(events + 1, events + cnt + 1);
int T = 0;
for (int i = 1; i <= cnt; i++) {
if (i == 1 || events[i].first != events[i-1].first) T += 2;
*events[i].second = T;
}
// 遠到近塗色
for (int i = 1; i <= n; i++)
update(1, T, cows[i].st, cows[i].ed, i, 1);
// 查詢每個時間點最終顏色
for (int i = 1; i <= T; i++)
visible[query(1, T, i, 1)] = true;
int ans = 0;
for (int i = 1; i <= n; i++) ans += visible[i];
cout << ans << '\n';
return 0;
}