hh 有一串由各種漂亮的貝殼組成的項鍊。hh 相信不同的貝殼會帶來好運,所以每次散步完後,他都會隨意取出一段貝殼,思考它們所表達的含義。hh 不斷地收集新的貝殼,因此,他的項鍊變得越來越長。有一天,他突然提出了乙個問題:某一段貝殼中,包含了多少種不同的貝殼?這個問題很難回答……因為項鍊實在是太長了。於是,他只好求助睿智的你,來解決這個問題。
輸入格式:
第一行:乙個整數n,表示項鍊的長度。
第二行:n 個整數,表示依次表示項鍊中貝殼的編號(編號為0 到1000000 之間的整數)。
第三行:乙個整數m,表示hh 詢問的個數。
接下來m 行:每行兩個整數,l 和r(1 ≤ l ≤ r ≤ n),表示詢問的區間。
輸出格式:
m 行,每行乙個整數,依次表示詢問對應的答案。
輸入樣例#1:
6輸出樣例#1:1 2 3 4 3 5
31 2
3 52 6
2資料範圍:24
對於100%的資料,n <= 500000,m <= 500000。
這個資料一看就不能暴力標記什麼的水過去
然後看到維護和詢問的區間資訊 所以很快想到了線段樹
關鍵是維護的序列是什麼呢?
我們選擇維護乙個1~n的序列 對每個點:為0表示此時下標表示的數不存在,為1表示此時下標表示的數存在
我們選擇離線做法,先記錄下每次詢問 一邊處理每個值 一邊查詢
將詢問按照右端點排序,now記錄當前訪問到的詢問
記last[i]陣列 表示 i上一次出現的位置(即截止目前最後出現的位置
用一遍for迴圈 update貝殼的編號進入序列 即update(1,i,1); 表示現在在當前位出現
然後將上一次出現i的位置重置為0 即 update(1,last[a[i]],0); 並記下i出現的當前新位置last[a[i]]=i;
對於詢問 每次從處理好的詢問中 找出右端點和當前處理位置相同的詢問 進行查詢
怎樣查詢呢?
因為每一次我們只記錄下了每個值最後出現的位置 以前的早已清零,所以查詢一段區間中有多少的不同值就是做區間求和
於是就變成線段樹的基本操作了ovo
注:1.注意線段樹中查詢操作的寫法
2.注意開夠陣列
貼個**
1 #include2 #include3 #include4 #include5 #include6view code#define n 500100
7#define lc p<<1
8#define rc p<<1|1
9using
namespace
std;
10int
n,m;
11int
a[n];
12struct
node
13t[n<<6
];16
17struct
pu18
q[n];
21bool cmp(pu a,pu b)
22bool cmp1(pu a,pu b)
2324
void pushup(int
p)27
void build(int p,int l,int
r)28
36void update(int p,int x,int
v)37
43int mid=t[p].l+t[p].r>>1;44
if(x<=mid) update(lc,x,v);
45else
update(rc,x,v);
46pushup(p);47}
48int query(int p,int ql,int
qr)49
59int last[2001000
];60
intmain()
6171 build(1,1
,n);
72int now=1
;73 sort(q+1,q+m+1
,cmp);
74for(int i=1;i<=n;i++)
7584
}85 sort(q+1,q+m+1
,cmp1);
86for(int i=1;i<=m;i++)
87 printf("
%d\n
",q[i].ans);
88return0;
89 }
SDOI2009 HH的項鍊 題解
題意 給乙個序列,長度為n,再給m個詢問,對每個詢問,輸出這個區間內有多少個不同的數。其實只需要把最後乙個出現的數統計一下就可以了,因為只有最後乙個出現的那個數才是有價值的,之前重複的數可以忽略,由此,演算法的框架就出來了,只需要有cdq的思想把查詢以區間的右端點為關鍵字排序,從前到後,同時用新出現...
SDOI2009 HH的項鍊 莫隊
hh有一串由各種漂亮的貝殼組成的項鍊。hh相信不同的貝殼會帶來好運,所以每次散步 完後,他都會隨意取出一段貝殼,思考它們所表達的含義。hh不斷地收集新的貝殼,因此,他的項鍊變得越來越長。有一天,他突然提出了乙個問題 某一段貝殼中,包含了多少種不同 的貝殼?這個問題很難回答。因為項鍊實在是太長了。於是...
SDOI2009 HH的項鍊 樹狀陣列
1972 sdoi2009 hh的項鍊 一段區間包含了多少種不同的數字 emmmm有很多種做法 莫隊 主席樹 線段樹.我覺得這題還挺好的 我比較弱就用的樹狀陣列 得離線 關鍵點是要將右端點r作為關鍵字 若前面出現過 就將其消掉 轉移到當前 for int i 1 i m i 這一坨把它比比划划就能明...