題目大意:給n個星星的座標,輸入保證縱座標y按非遞減序輸入,並且不會兩個星星位置重複。如果某個星星左下角(包含邊界)共包含k個星星,則成該星星的等級爲k。分別輸出0~n-1等級的星星數量
解題思路:雖說這是道樹狀數組的入門題,但仍沒反應過來。個人理解是:c數組維護的是<=idx的前綴和,每次將橫座標爲x加入的時候可以先查詢一下目前小於等於x的個數,這個利用getsum求得,然後用hash數組+1,之後要將這個x單點更新一下,也就是x位置單點+1。(之前有個疑惑,前綴和和這個排名有什麼關係呢?是這樣子的,下標爲k的前綴和由於我們每次單點更新+1,這樣getsum求出來的前綴和一定<=k,每次add(idx,1)表示之後只要比idx大的,也就是橫座標比它大的都能得到我這個1的貢獻。那麼getsum也就轉化成了取<=k的點的貢獻,也就是我們要求得的東西。這和求那個逆序數的思路很像,但是比那個好理解,注意轉化那邊,二維其實就是一維的拓展)。本題注意橫座標從0開始,要+1,否則樹狀數組步驟會死循環。
AC代碼:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <utility>
using namespace std;
const int maxn = (int)32e3+5;
int c[maxn],ans[maxn],n;
inline int lowbit (int x) {
return x & (-x);
}
void add (int idx, int num) {
while (idx <= maxn) {
c[idx] += num;
idx += lowbit(idx);
}
}
int get_sum (int idx) {
int k = 0;
while (idx > 0) {
k += c[idx];
idx -= lowbit(idx);
// idx &= idx - 1;
}
return k;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int x,y;
while (cin >> n) {
memset(c,0,sizeof(c));
memset(ans,0,sizeof(ans));
for (int i = 1; i <= n; i++) {
cin >> x >> y;
x++;//x座標從0開始
add(x,1);
ans[get_sum(x)]++; //getsum的含義是橫座標<=n的星星個數之和,這個和在這裏表示等級 ans表示每個等級的個數
}
for (int i = 1; i <= n; i++) {
cout << ans[i] << '\n';
}
}
return 0;
}