HDU1541、POJ2352(樹狀數組入門題)

題目鏈接POJ2352,HDU1541

題目大意:給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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章