由於詢問的是區間中貝殼的種類數,所以問詢區間中相同種類的貝殼只有乙個會起作用
將i位置的貝殼前一次出現的位置記作pre[i],種類為x的貝殼最後一次出現的位置記作f[x],類似於鄰接表的nxt和had,利用pre[i]=f[x],f[x]=i來處理pre
對於每個詢問[l,r],只有pre[i]也就是說所處位置為i的貝殼要想起作用,需要滿足兩個條件:條件① i必須滿足l<=i<=r 條件② pre[i]必須滿足pre[i]我們可以將位置i是第j個詢問[l,r]的邊界稱為位置i和詢問j相對應(1<=i<=n,1<=j<=m)
顯然乙個位置可以對應任意個詢問(這個問題會在後面解決),乙個詢問只能對應兩個位置
可以用離線演算法,用乙個陣列vec[i]來記錄位置和對應的詢問的關係(由於會用到vector,所以我用vec來命名)
乙個vec[i]包含兩個資訊:
①vec[i].num表示位置i所對應的詢問所對應的有關資料(這不廢話嗎 -_-||)(這句話是什麼意思呢?假設位置i對應了詢問j,而且位置i是詢問j的左邊界,那麼vec[i].num=j*2,如果位置i是詢問j的右邊界,那麼vec[i].num=j*2+1。那這是幹什麼用的呢?)
②vec[i].to表示位置i所對應的區間[l,r]的左邊界l-1,即vec[i].to=l-1(這是幹什麼用的呢?由於被選中的貝殼必須要滿足上面提到的兩個條件,所以對於每個詢問,只需要用樹狀陣列查詢有多少個pre[i]滿足0<=pre[i]<=l-1(l<=i<=r)即可)
由於乙個位置可以對應任意個詢問,所以可以在原來的vec[i]上再加一維vec[i][j],j表示與位置i所對應的多個詢問中的第j個詢問(0<=j在上面提到:對於每個詢問,只需要用樹狀陣列查詢有多少個pre[i]滿足0<=pre[i]<=l-1(l<=i<=r)即可,所以樹狀陣列的query(x)表示滿足0<=pre[i]<=x的i的個數(也可以是滿足上述條件的pre[i]的個數,其實都一樣的,因為乙個i對應乙個pre[i]嘛)(這裡i的範圍可以有兩種,對應著兩種操作:操作①一次性把所有的滿足0<=pre[i]<=x的i的個數都加進樹狀陣列中,然後再掃瞄詢問計算每個詢問的結果,這樣的話i的範圍是(1<=i<=n)。操作②邊掃瞄每個詢問邊把pre[i]加進樹狀陣列,這樣的話i的範圍就是(1<=i<=p)
那麼操作①和操作②到底選哪種,就取決於我們需要i滿足什麼樣的範圍,滿足0<=pre[i]<=l-1(l<=i<=r)的i的數量可以用滿足0<=pre[i]<=l-1(1<=i<=r)的i的數量減去滿足0<=pre[i]<=l-1(1<=i<=l-1)的i的數量得到
由於上面所需的兩個範圍(1<=i<=r)和(1<=i<=l-1)的兩個上界r和l-1都不等於n,所以我們選用操作②
具體實現:用指標i掃瞄1到n每個位置,邊掃邊把pre[i]加到樹狀陣列裡,如果當前的位置i是詢問j的左邊界,此時vec[i][j].to為l-1,那麼query(vec[i][j].to)的值就是滿足0<=pre[i]<=l-1(1<=i<=l-1)的i的數量,這時候vec[i][j].num的作用就體現出來了,因為位置i是詢問j的左邊界,所以vec[i][j].num的值為j*2,用乙個陣列ans來記錄每個詢問的答案資訊,對於每個詢問j,將ans[j*2]賦值為query(l-1),即ans[vec[i][j].num]=query(vec[i][j].to)。同理,當指標i為詢問j的右邊界r時,query(vec[i][j].to)的值就是滿足0<=pre[i]<=l-1(1<=i<=r)的i的數量,vec[i][j]的值就是j*2+1,進行相同的處理,等到全部掃瞄完時,列舉每個詢問,這時詢問j的答案就是ans[j*2+1]-ans[j*2],輸出即可。
(由於某種貝殼第一次出現時此位置的pre值為0,且lowbit(0)等於0,在query()函式中會死迴圈,所以在呼叫和pre有關的判斷時都在原本的值上+1,即可解決,共有兩處需要加一,乙個是將pre加入樹狀陣列時給pre加一,乙個是判斷pre是否滿足0<=pre<=l-1時給右邊界加一(為什麼左邊界不用加一?這裡可以自己想一想))
#include #include #include #include using namespace std;
int read()
while(c>='0'&&c<='9')
return f*x;
}const int n=1e6+5;
int tre[n],pre[n],f[n],a1,ans[n],n,m,l,r;
struct tree
;vector vec[n];
int lowbit(int x)
void update(int x,int y)
int query(int x)
int main()
m=read();
for(int i=1;i<=m;i++)
); vec[r].push_back((tree));
} for(int i=1;i<=n;i++) //這裡的i就是上文的指標p
for(int i=1;i<=m;i++) cout
}
HH的項鍊 樹狀陣列
code 我洛谷部落格 點這裡某一段貝殼中,包含了多少種不同的貝殼?最開始看見這道題時,沒有思路 但再看看,可以非常明了的發現這是乙個樹狀陣列ban題 設有一長為5的項鍊 1 2 3 2 1 然後 m 3 1 52 5 1 3我的思路是這樣,由於要求的是種類數 求l 到 r 的個數 每種貝殼只能存乙...
HH的項鍊 樹狀陣列
我csdn部落格 點這裡某一段貝殼中,包含了多少種不同的貝殼?最開始看見這道題時,沒有思路 但再看看,可以非常明了的發現這是乙個樹狀陣列ban題 設有一長為5的項鍊 1 2 3 2 1 然後 m 3 1 52 5 1 3我的思路是這樣,由於要求的是種類數 求l 到 r 的個數 每種貝殼只能存乙個 不...
2725 HH的項鍊(樹狀陣列)
題目描述 hh有一串由各種漂亮的貝殼組成的項鍊。hh相信不同的貝殼會帶來好運,所以每次散步完後,他都會隨意取出一段貝殼,思考它們所表達的含義。hh不斷地收集新的貝殼,因此,他的項鍊變得越來越長。有一天,他突然提出了乙個問題 某一段貝殼中,包含了多少種不同的貝殼?這個問題很難回答。因為項鍊實在是太長了...