計蒜客 項鍊 (主席樹 離線 樹狀陣列)

2021-09-19 11:33:52 字數 1727 閱讀 4708

題目大意就跟洛谷的hh項鍊一樣,但是求一串區間內不重複數字的和。

一種做法是離線 + 樹狀陣列,這裡不講。

主要講一下新學習的技能,用主席樹搞區間內不重複的數字(個數或者和)。

由於洛谷那個寫炸了,一直mle(不知道被什麼資料卡了),只好拿計蒜客上面的題來試一下,結果計蒜客的能過。

主席樹做法和樹狀陣列相同,對於同乙個數字,我們只紀錄最後乙個出現的位置,如果前面出現了,我們先把他刪掉,然後再在現在這個位置加上1。

為什麼只記錄最後一次出現的位置?因為當我們維護到 i 這個位置的時候,如果a[i] 在前面出現過,我們肯定只能保留乙個,而對於當前我們維護的區間來說,越後面對答案貢獻越大(這個地方有點類似單調佇列,當數值相同的元素入隊,把先入隊的去掉,留下**隊的,因為**隊的更「新鮮」,對答案貢獻更大)。

其實也很容易想的,對於離線的樹狀陣列來說,前面的區間我們已經全部查詢過,對於當前查詢的區間,如果當前更新的位置的值已經出現過,它有可能出現在我們查詢的區間 [l,r]的前面,導致我們查不到,因此離線情況下我們每次保留最後乙個,使得它對查詢的區間總是有貢獻,並且把前面的刪掉,使得答案不會重複。

關於查詢,給出要查詢的區間【l,r】,我們只需要查第r棵樹,【l,n】區間內的所有答案就行了。這一點需要對主席樹有一定理解。因為第r棵樹是我們維護了前r個數字的樹,但它包括了前l個數字,怎麼辦?前面講到這裡的主席樹,建的線段樹也是用區間建的。也就是我們可以在第r棵樹內查詢區間【l,r】,即是答案。

為了方便我們可以直接查詢區間【l,n】,因為r後面的數字在第r棵樹沒有維護,【l,n】就相當於【l,r】。

那怎麼維護區間內不同數字的和呢?(思考)

(一如既往的廢話連篇的部落格。。。主要是為了能看懂)

**:

#include

using

namespace std;

const

int maxn =

5e4+1;

struct sstree[maxn *50]

;int n,m,x,last[maxn *2]

,a[maxn]

,root[maxn]

,sz;

void

init()

; root[0]

=0;}

void

update

(int

&rt,

int k,

int l,

int r,

int v)

int mid = l + r >>1;

if(k > mid)

update

(tree[rt]

.rs,k,mid +

1,r,v)

;else

update

(tree[rt]

.ls,k,l,mid,v)

; tree[rt]

.val = tree[tree[rt]

.ls]

.val + tree[tree[rt]

.rs]

.val;

}int

query

(int rt,

int x,

int l,

int r)

intmain()

scanf

("%d"

,&m)

;for

(int i =

1; i <= m; i++

)return0;

}

計蒜客習題 校長的問題 樹狀陣列 離線查詢

由於蒜廠沒法複製 題意就是給你n個按學號排序的成績 m個查詢 a b 意思為學號為前a名同學有多少前b名成績 就是用樹狀陣列維護每個數字出現多少次 對於查詢我們進行離線操作 第一次接觸 以後要掌握 就可以解決了 這是我第一道離線查詢的題目希望能掌握 by ljjjjjq include includ...

SPOJ DQUERY 離線樹狀陣列or主席樹

給出n個數,問區間 l,r 中有多少不同的數。經典題。可以離線 樹狀陣列,離線儲存查詢,按照r排序,用last陣列儲存每個數最接近當前詢問r的位置。也可以主席樹,從右到左建樹,pos儲存每個數字的當前最左位置,每次在新版本的線段樹中在當前位置 1,然後把舊版本中該樹的位置 1.離線 樹狀陣列 inc...

計蒜客 樹狀陣列線段樹 帕吉的肉鉤

分析題意,是一道典型的線段樹題目.要求做到區間賦值 樹狀陣列應該無法做到 區間求和兩個操作.開始的時候思路不清楚,後來要注意線段樹的 up 和 down 操作.需要注意的是有lazy tag的節點,它本身的資訊是完全正確的,子節點的資訊是待更新的.這也就是說,當需要用到這些子節點的資訊時在進行更新....