1. 程式人生 > >洛谷P1972 [SDOI2009]HH的項鍊(樹狀陣列)

洛谷P1972 [SDOI2009]HH的項鍊(樹狀陣列)

題目連結:

https://www.luogu.org/problemnew/show/P1972

題目描述:

HH 有一串由各種漂亮的貝殼組成的項鍊。HH 相信不同的貝殼會帶來好運,所以每次散步完後,他都會隨意取出一段貝殼,思考它們所表達的含義。HH 不斷地收集新的貝殼,因此,他的項鍊變得越來越長。有一天,他突然提出了一個問題:某一段貝殼中,包含了多少種不同的貝殼?這個問題很難回答……因為項鍊實在是太長了。於是,他只好求助睿智的你,來解決這個問題。

輸入輸出格式

輸入格式:

第一行:一個整數N,表示項鍊的長度。

第二行:N 個整數,表示依次表示項鍊中貝殼的編號(編號為0 到1000000 之間的整數)。

第三行:一個整數M,表示HH 詢問的個數。

接下來M 行:每行兩個整數,L 和R(1 ≤ L ≤ R ≤ N),表示詢問的區間。

 

輸出格式:

M 行,每行一個整數,依次表示詢問對應的答案。

輸入輸出樣例

輸入樣例#1:
6
1 2 3 4 3 5
3
1 2
3 5
2 6
輸出樣例#1:
2
2
4

說明

資料範圍:

對於100%的資料,N <= 500000,M <= 500000。

解題思路:

離線處理,邊更新邊查詢。以右端點升序更新所有查詢的區間。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define lowbit(x) (x&(-x))
 5 using namespace std;//區間查詢 
 6 int C[500010];
 7 int ans[500010],num[500010];
 8 int booll[1000010];//位置
 9 struct Quiry{
10     int l,r;
11     int pos;
12     bool operator < (const Quiry q) const
{ 13 return r<q.r;//只需要保證右邊升序即可 14 } 15 }q[500010]; 16 void add(int x,int v){ 17 for(int i=x;i<=500010;i+=lowbit(i)){ 18 C[i]+=v; 19 } 20 } 21 int getSum(int x){ 22 int sum=0; 23 for(int i=x;i>0;i-=lowbit(i)){ 24 sum+=C[i]; 25 } 26 return sum; 27 } 28 int main(int argc, char** argv) { 29 //離線做 30 int n; 31 scanf("%d",&n); 32 for(int i=1;i<=n;i++){ 33 scanf("%d",&num[i]); 34 } 35 int m; 36 scanf("%d",&m); 37 for(int i=1;i<=m;i++){ 38 scanf("%d %d",&q[i].l,&q[i].r); 39 q[i].pos=i; 40 } 41 sort(q+1,q+m+1); 42 //邊更新樹狀陣列,邊查詢 43 int next=1; 44 for(int i=1;i<=m;i++){ 45 for(int j=next;j<=q[i].r;j++){ 46 if(booll[num[j]]){ 47 add(booll[num[j]],-1); 48 } 49 add(j,1);//位置 50 booll[num[j]]=j; 51 } 52 next=q[i].r+1; 53 54 ans[q[i].pos]=getSum(q[i].r)-getSum(q[i].l-1); 55 } 56 for(int i=1;i<=m;i++) printf("%d\n",ans[i]); 57 58 return 0; 59 }

 參考自:https://www.luogu.org/blog/little-black/solution-p1972