1. 程式人生 > >HDU 4417 —— Super Mario(樹狀陣列,離散化,離線處理)

HDU 4417 —— Super Mario(樹狀陣列,離散化,離線處理)

意思比較簡單,就是給N個數(下標從0開始),然後q個詢問,三個引數,L,R,H,詢問序列中在【L,R】這個區間上小於等於H的個數。

挺綜合的一道題目。因為數字最多100000個,數值最多達10^9,所以首先要對數值進行離散化。

像這種區間查詢問題,用S(X,H)表示從0開始到X,小於等於H的個數,那麼每個查詢就可以轉化成S(R,H)-S(L-1,H),這個直接寫成樹狀陣列或線段樹是比較困難的。

轉成離線處理會比較簡單。具體來說就是把每個查詢拆成兩個事件,一個對應L,一個對應R,一共有2q個事件,將所有事件從左到右排序,如果對應的位置相同,那麼對應左端點的應該優先在前。

然後就是遍歷0~N-1,遇到事件左端點的,用k表示H在離散化之後對應的下標,減掉SUM(k),把a[i]對應的位置新增到樹狀陣列中,遇到右端點,就加上SUM(k)。

這樣,由於到了某個i的時候,後面的數值還沒加進來,所以對當前值沒有影響,求出來的SUM自然就是對應0到當前端點的值。

最後在一口氣將所有答案輸出即可。

具體還是見程式碼吧。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100000
#define M 200010
struct Event{
	int type;//事件型別,0表示左端點,1表示右端點
	int id;//事件對應的查詢的編號
	int x;//事件對應的端點
	int v;//事件對應的H值
	bool operator < (const Event& tmp)const{
		if(x==tmp.x)	return type<tmp.type;
		return x<tmp.x;
	}
}ev[M];
inline void in(int& num){
	char c=getchar();
	num=0;
	while(c<48 || c>57)	c=getchar();
	while(c>=48 && c<=57){
		num = num*10+c-48;
		c = getchar();
	}
}
int t, ct, n, m, q, p, l, r, x, i, j, k;
int a[N], b[M], s[M], ans[N];
void add(int v){
	for(;v<=m;v+=(v&(-v)))	s[v]++;
}
int sum(int v){
	int res=0;
	for(;v;v-=(v&(-v)))	res+=s[v];
	return res;
}
int main(){
	in(t);
	for(ct=1; ct<=t; ct++){
		in(n); in(q);
		m=0;
		for(i=0; i<n; i++){
			in(a[i]);
			b[m++]=a[i];
		}
		for(i=0; i<q; i++){
			in(l); in(r); in(x);
			ev[i<<1].type=0; ev[i<<1].id=i; ev[i<<1].x=l; ev[i<<1].v=x;
			j = (i<<1)|1;
			ev[j].type=1; ev[j].id=i; ev[j].x=r; ev[j].v=x;
			b[m++] = x;
		}
		p = q<<1;
		sort(ev, ev+p);
		sort(b, b+m);
		m = unique(b, b+m)-b;
		memset(s,0,sizeof(s));
		j=0;
		for(i=0; i<n; i++){
			//先處理掉左端點
			while(j<p && ev[j].type==0 && ev[j].x==i){
				k = lower_bound(b, b+m, ev[j].v)-b+1;
				ans[ev[j].id] = 0 - sum(k);
				j++;
			}
			//更新當前的a[i]
			k = lower_bound(b, b+m, a[i])-b+1;
			add(k);
			//處理右端點
			while(j<p && ev[j].type==1 && ev[j].x==i){
				k = lower_bound(b, b+m, ev[j].v)-b+1;
				ans[ev[j].id] += sum(k);
				j++;
			}
		}
		printf("Case %d:\n", ct);
		for(i=0; i<q; i++)	printf("%d\n", ans[i]);
	}
	return 0;
}