洛谷 P1972 SDOI2009 HH的項鍊

2022-05-21 20:48:08 字數 1548 閱讀 2062

p1972 [sdoi2009]hh的項鍊

法一:樹狀陣列,離線

翻譯:給出乙個數列a[n]還有許多請求,請求由l,r兩個數組成,要求對於每個請求輸出數列中從a[l]到a[r]中不重複的數的個數。

方法:首先讀入數列a[n],並預處理next1,boo兩個輔助陣列,方法見程式。

然後讀入請求,把請求按l從小到大排序,並記錄原來序號方便輸出。

(本題中,為了方便說明,用tree[i]表示可通過sum(i,i)求出的樹狀陣列中第i項的值(不是指c[i]))

開始前,對於每個第一次出現的數所在的位置t,使tree[t]++,即add(t,1)。這樣,如果請求的l是1,就可以通過sum(l,r)得出答案。但是,如果請求的左端點大於1,就不能這樣做了。

例如,當請求的l是5時,在a[5]到a[r]中,可能有一些數與a[1]到a[4]中的數相同,且它們如果從第1個數開始數不是第一次出現的,但如果從第5個數開始數就是第一次出現的。因此,在處理這個請求的時候,就需要先找到tree[1]到tree[4]中所有不為0的數tree[x],先將tree[x]減1(由於tree[1]到tree[4]實際上不會影響sum(5,r)的結果,因此不減也沒關係),再找到與a[x]相同的下乙個數t,也就是next1[x]的值,然後將tree[t]加1(如果next1[x]為0,指的就是沒有下乙個與a[x]相同的數,則不需進行此操作)。例如有乙個數tree[1]為1,那麼就先將tree[1]減1(不減也行),然後如果next1[1]不為0,則將tree[next1[1]]加1。

由此可得出,需要按排序後的順序來處理請求,對於請求q[i],如果q[i-1].l

最後不要忘了按原來的詢問順序輸出結果。

#include#includeusing namespace std;

typedef long long ll;

ll a[51000];

ll c[400100];

ll next1[51000];//next1[i]記錄第i個數字下一次出現的位置

ll ans[201000];

ll boo[1001000];//boo[i]記錄數字i第一次出現位置

ll n,m,x,k=1,lastk;

struct query1

return ans;//曾經忘記返回值

}ll sum(ll l,ll r)

int main()

for(i=n;i>=1;i--)//優化為倒序

next1[i]=boo[a[i]],boo[a[i]]=i;//方便找到某數字第一次出現位置與下一次出現的位置(鏈式的),弄幾組資料試試就能明白

for(i=1;i<=n;i++)

if(boo[a[i]]==i)

add(i,1);

scanf("%lld",&m);

for(i=1;i<=m;i++)

sort(q+1,q+m+1);

for(i=1;i<=m;i++)

{//if(q[i].l>q[i-1].l)//後面去掉的,因為沒用

//{lastk=k;

k=q[i].l;

for(j=lastk;j法二:莫隊演算法

洛谷P1972 SDOI2009 HH的項鍊

這道題想了很久,發題解是為了理解的更深刻一點。管理放我過好嘛qwq 步入正題 這道題應該是很多做法,我選擇的是離線 樹狀陣列。首先輸入陣列。用fisrt陣列先記錄元素最開始出現的位置,對應的每乙個樹狀陣列的位置add一下 樹狀陣列洛谷也有模板題的了解一下就ok啦 rep i,1 n 然後倒著更新一遍...

洛谷P1972 SDOI2009 HH的項鍊

題目描述 p1972 sdoi2009 hh的項鍊 hh 有一串由各種漂亮的貝殼組成的項鍊。hh 相信不同的貝殼會帶來好運,所以每次散步完後,他都會隨意取出一段貝殼,思考它們所表達的含義。hh 不斷地收集新的貝殼,因此,他的項鍊變得越來越長。有一天,他突然提出了乙個問題 某一段貝殼中,包含了多少種不...

洛谷 P1972 SDOI2009 HH的項鍊

1.按每個要求的區間的右端點排序一下 2.樹狀陣列tree j 維護從1到j區間內不同數字的個數有多少個 3.然後用字首和的思想就好 tree r tree l 1 1 include2 include3 include4 define maxn 1000002 5 define next nex ...