線段樹大概地球人都知道了,就是以陣列的下表建立線段樹來進行一些區間操作,這裡介紹一下權值線段樹,顧名思義,其實權值線段樹也是線段樹的一種。
一:權值線段樹線段樹與簡單線段樹的區別就像他的名字一樣,他的葉子節點存的並不是陣列的下表,而是陣列中數的權值,這種操作很簡單的解決一些問題。
二.例題分析
1.求逆序對數(hdu 1394)
好吧,其實這種題直接用歸併就可以解決嗎,但是我們呢偏要任性用權值線段樹解決
每次插入乙個數,然後統計他前邊的數比他的個數,例如當我們插入的數是x,那麼我們找x+1~n裡邊已經存在的數的個數就可以了
ac**:
#include #include #include using namespace std;
const int maxn=5005;
struct node
data[4*maxn];
void build(int id,int l,int r)
int query(int id,int l,int r)
int a[maxn];
int main()
cout<
題目描述:你知道有乙個1~n的排列,但具體排列你不知道。現在給出1~n每個字首的逆序數對數,讓你還原這個排列
把第乙個問題反過來了,知道逆序數讓我們求解序列,我們從後往前看,設字首陣列為p那麼對於第i個數來說sum=p[i]-p[i-1]表示的恰好就是他的前邊比他大的數的個數,所以該位置的數字就是剩下的這些數字裡的第i-sum大的數字。於是我們把1~n構建一棵權值線段樹。初始化每個數字的權值都是1。然後從n~1處理。每一次都query取出第i-sum大的數字作為當前位置的答案,然後update將該數字從該權值線段樹刪除,然後到前乙個位置繼續相同操作。最後就能得出這樣乙個正確的排列了。
ac**:
#include#include#include#define clr(x) memset(x,0,sizeof(x))
using namespace std;
struct segtree
tree[400010];
int n,m,rev[50010],ans[50010];
void init(int i,int l,int r)
int mid=(l+r)>>1;
init(i<<1,l,mid);
init((i<<1)|1,mid+1,r);
}int query(int i,int k)
void update(int i,int pos)
int main()
for(int i=1;i缺點:在資料很大的時候,空間可能會爆,需要離線化處理
權值線段樹
維護全域性的值域資訊,每個節點記錄的是該值域的值出現的總次數。使用二分的思想 離散化的時候,需要用到 支援查詢全域性k小值,全域性rank,前驅,後繼等。單詞操作時間複雜度為o logn 空間複雜度為o n 相對於平衡樹的優勢 簡單,速度快 劣勢 值域較大時,我們需要離散化,變成離線資料結構 我認為...
權值線段樹
include using namespace std int n,m,tre 10003 4 laz 10003 4 void pushdown int num void update int num,int le,int ri,int x,int y,int z pushdown num int...
權值線段樹
權值線段樹是線段樹的一種,但是它與線段樹不同 線段樹的每個結點是用來維護一段區間的最大值或總和 而權值線段樹的每個結點儲存的一段區間有多少個數 權值線段樹主要用來查詢區間第k大或者第k小的值 現在有乙個陣列x 10 對陣列排序後為x 10 每個數的個數如下 1 32 2 3 24 1 5 18 1 ...