首先要知道權值線段可以處理全域性第 k 大;主席樹可以處理靜態區間第 k 大,所謂靜態就是不能改變值;但是如果有修改操作,用主席樹做,每次要修改,後面的所有主席樹都要進行一次修改,複雜度為 o(n); 顯然是不行的;
這裡就可以用到樹狀陣列維護字首和,權值線段樹維護區間資訊;
換句話說就是樹狀陣列每個結點換成權值線段樹,主體思想還是跟主席樹一樣,利用字首和求某個區間第 k 大(或者其他操作);
全部**都是這道題:
dynamic rankings
個人認為最難理解的就是建樹部分,這建樹還是跟主席樹一樣的思想,只是第 i 顆樹不再是第 i-1 顆樹轉化過來,而是第 i 顆樹轉化過來,也就是說當你又更新第 i 顆樹時,第 i 棵樹要從原來的第 i 顆樹轉化過來;
例如:又更新第 i 棵樹的某個值,只要在原來的第 i 棵樹上再加一條鏈就行;跟主席樹的思路還是一樣的;
int
update
(int pre,
int l,
int r,
int pos,
int s)
return rt;
}void
add(
int p,
int q)
}
查詢操作,跟主席樹的思路還是一樣的,只不過不再是 sum[l[nw]]-sum[l[pre]];(這裡的nw代表第 r 棵樹的根結點,pre代表第 l 棵樹的根結點);
而是根據樹狀陣列求出要算的 l ,和要算的 r,然後迴圈加上減去就行;
**:
int
query
(int l,
int r,
int k)
else
}
總**:
#include
#define ll long long
#define pa pair
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using
namespace std;
const
int n=
100100
;const
int m=
10000000
;const ll mod=
100000000
;int n,m,cnt,tot,a[n*2]
,b[n*2]
,c[n*2]
,tr[n*2]
,l[n*
400]
,r[n*
400]
,sum[n*
400]
;struct nodeque[n]
;//問題
vector<
int>vl,vr;
intlowbit
(int k)
intupdate
(int pre,
int l,
int r,
int pos,
int s)
return rt;
}void
add(
int p,
int q)
}int
query
(int l,
int r,
int k)
else
}int
main()
int ge=n;
for(
int i=
1;i<=m;i++
)sort
(b+1
,b+ge+1)
; cnt=
unique
(b+1
,b+ge+1)
-b-1
;for
(int i=
1;i<=n;i++
)add
(i,1);
for(
int i=
1;i<=m;i++
)while
(que[i]
.r)printf
("%d\n"
,b[query(1
,cnt,que[i]
.k)]);
}else
}return0;
}
權值線段樹套序列線段樹
p3380 模板 二逼平衡樹 樹套樹 主要思路如下 外層為權值線段樹,內層為動態開點線段樹,也就是每個權值線段樹上的節點開乙個動態開點線段樹。外層的權值線段樹支援查詢排名,內層的線段樹限制了區間。實際上就是在普通權值線段樹上查詢的價值變成了在其線段樹上區間查詢返回的值。對於這道模板題,我們先寫幾個函...
學習筆記 權值線段樹
雖然題解很多,也有權值線段樹,但我的和他們似乎不盡相同,跑的也挺快。所謂權值線段樹,就是用線段樹來儲存權值。那什麼是權值呢?似乎小學初中學統計的時候了解到,他是描述數在資料中比例大小的量,這裡用作此數出現的次數。做法顯然。我們用 cnt i 表示第 i 個數出現的次數,那麼可以這樣 void upd...
權值線段樹學習筆記
定義 struct segmenttree tree maxn 2 建樹 void build int p,int l,int r int mid l r 1 build lson,l,mid build rson,mid 1,r pushup 單點更新 void change int p,int ...