題目大意就跟洛谷的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的節點,它本身的資訊是完全正確的,子節點的資訊是待更新的.這也就是說,當需要用到這些子節點的資訊時在進行更新....