農夫約翰的 N 隻奶牛各自偏好一段草地區間 [S, E]。若牛 i 的區間 [Si, Ei] 完全包含牛 j 的區間 [Sj, Ej](即 Si ≤ Sj 且 Ej ≤ Ei,且區間長度嚴格大於),則稱牛 i 比牛 j 強。請對每隻奶牛,計算有多少隻奶牛比它強。輸入包含多組測試數據,N ≤ 10^5,坐標範圍 0 ≤ S < E ≤ 10^5,以 0 結束輸入。
將每個區間 [S, E] 視為二維平面上的點 (S, E)。條件「Si ≤ Sj 且 Ej ≤ Ei」等價於:點 i 在點 j 的左上方(x 坐標較小,y 坐標較大)。因此,問題轉化為:對每個點,統計其左上方有多少個點。這正是經典問題 HDU 1541 Stars(統計左下方點數)的變形。
Stars 題中點已按 y 升序、x 升序給出,直接用樹狀數組維護 x 坐標前綴和。本題點無序,需自行排序:
題目要求「S 和 E 相同不計在內」。排序後相同區間相鄰,查詢時若發現與前一個點坐標完全相同,直接沿用前一個點的查詢結果,不重複更新樹狀數組(或更新後再查詢下一個),從而排除相同區間互相計數。
坐標上限 10^5,加上樹狀數組下標從 1 開始,需將所有 S、E 統一 +1 避免 0 下標;若坐標範圍更大則需離散化壓縮。
struct node { int x, y, id; } a[100005];
int n, bit[100005], ans[100005];
bool cmp(node a, node b) {
if (a.y != b.y) return a.y > b.y; // y 降序
return a.x < b.x; // x 升序
}
int lowbit(int x) { return x & -x; }
void update(int i, int v) {
for (; i <= 100005; i += lowbit(i)) bit[i] += v;
}
int query(int i) {
int s = 0;
for (; i > 0; i -= lowbit(i)) s += bit[i];
return s;
}
int main() {
while (scanf("%d", &n), n) {
memset(bit, 0, sizeof(bit));
for (int i = 0; i < n; ++i) {
scanf("%d%d", &a[i].x, &a[i].y);
a[i].id = i;
++a[i].x; ++a[i].y; // 離散化/避免 0
}
sort(a, a + n, cmp);
ans[a[0].id] = query(a[0].x);
update(a[0].x, 1);
for (int i = 1; i < n; ++i) {
if (a[i].x == a[i-1].x && a[i].y == a[i-1].y)
ans[a[i].id] = ans[a[i-1].id];
else
ans[a[i].id] = query(a[i].x);
update(a[i].x, 1);
}
for (int i = 0; i < n; ++i) {
if (i) printf(" ");
printf("%d", ans[i]);
}
puts("");
}
return 0;
}
樣例輸入:
3 1 2 0 3 3 4 0
點集:(1,2)、(0,3)、(3,4)。排序後 y 降序:(3,4)、(0,3)、(1,2)。
按原序輸出:牛0(1,2)→1,牛1(0,3)→0,牛2(3,4)→0,符合樣例輸出 1 0 0。
本題巧妙將區間包含問題轉化為二維偏序統計,通過排序規則統一處理方向,配合樹狀數組實現高效動態前綴和查詢,是「Stars 類問題」的經典變形應用。關鍵點在於排序順序的選擇、相同區間的去重處理,以及坐標偏移避免下標為 0。