入門博文:
共同點:同時乙個節點維護多個葉子節點的資訊
不同點:線段樹節點採用二分的規則,而樹狀陣列節點利用了bit位的性質來鎖定管理的葉子節點,且樹狀陣列只能直接查詢1~i區間的資訊,而線段樹可以直接查詢[l,
r]
[l,r]
[l,r
] 區間資訊,
樹狀陣列可以解決問題的思路推廣到線段樹都可以用線段樹解決。不過樹狀陣列**量是真的小!
樹狀陣列核心函式:
這樣的**要求其葉子節點必須從1開始(因為此處維護的都是1~i的資訊,可以改下**使維護0到i的資訊,不過**就不簡潔了)
int
lowbit
(ll val)
intgetsum
(ll k)
//遍歷1~k區間的管理節點。
return ans;
}void
modify
(ll k,ll val)
//向上更新管理葉子節點k的節點資訊。
}
洛谷模板題,改點查段:
#include
#define mset(a,b) memset(a,b,sizeof(a))
using
namespace std;
typedef
long
long ll;
const
int maxn=
5e5+
100;
ll qwe[maxn]
,n,q;
intlowbit
(ll val)
intgetsum
(ll k)
return ans;
}int
modify
(ll k,ll val)
}int
main()
while
(q--
)else
}return0;
}
比如:lis(最長遞增子串行),求逆序對,改點查段,改段查點的問題都可以用樹狀陣列解決。
lis(最長遞增子串行)思想:f[i
]f[i]
f[i]
表示當前以值 i
ii 為遞增子串行末尾的序列最長長度。每個葉子 i
ii 記錄當前f[i
]f[i]
f[i]
, 最大值,那麼用樹狀陣列節點維護其葉子節點的最大值即可。如果該此時序列中數字值為val,那麼f[v
al]=
max(
f[i]
)i∈[
1,va
l]+1
=get
max(
i)+1
f[val]=max(f[i])_+1 =\ \ ~getmax(i)+1
f[val]
=max
(f[i
])i∈
[1,v
al]
+1=g
etma
x(i)
+1ps:有時候需要離散化,所以還是二分求lis比較好用
求逆序對思想:
每個葉子 i
ii 記錄當前值i的出現次數,那麼用樹狀陣列節點維護其管理的葉子節點出現次數和即可,假設當前第k個數其值為val,那麼前面大於val的個數=k−1
−get
sum(
val)
k-1-getsum(val)
k−1−ge
tsum
(val
)
#include
#define mset(a,b) memset(a,b,sizeof(a))
using
namespace std;
typedef
long
long ll;
const
int maxn=
5e5+
100;
int tot,n;
int unq[maxn]
,qwe[maxn]
,bt[maxn]
;int
getind
(int val)
intlowbit
(int val)
ll getsum
(int k)
return ans;
}void
modify
(int k)
//k葉子+1
}int
main()
cout<}
改段查點:
修改:將區間 $[l,r] $ 的每個數加val,查詢:求點k處的值
假設原陣列為num
[]
numnu
m[],我們用d[]
dd[
] 記錄相鄰元素的差值,比如d[i
]=nu
m[i]
−num
[i−1
]d[i]=num[i]-num[i-1]
d[i]=n
um[i
]−nu
m[i−
1],且我們讓 d[1
]=nu
m[1]
d[1]=num[1]
d[1]=n
um[1
] ,那麼num
[i]=
d[1]
+d[2
]...
..+d
[i
]num[i]=d[1]+d[2].....+d[i]
num[i]
=d[1
]+d[
2]..
...+
d[i]
至於修改操作,我們只需將d[l
]d[l]
d[l]
加上v al
valva
l,d[r+
1]
d[r+1]
d[r+1]
減去v al
valva
l即可,
我們維護d陣列即可。
洛谷模板:
**:
// luogu-judger-enable-o2
#include
#define mset(a,b) memset(a,b,sizeof(a))
using
namespace std;
typedef
long
long ll;
const
int maxn=
5e5+
100;
ll qwe[maxn]
,n,q;
intlowbit
(ll val)
intgetsum
(ll k)
return ans;
}void
modify
(ll k,ll val)
}ll va[maxn]
;int
main()
modify(1
,va[1]
);for(
int i=
2;i<=n;
++i)
modify
(i,va[i]
-va[i-1]
);while
(q--
)else
}return0;
}
樹狀陣列總結
樹狀陣列的基本知識已經被各種大牛和菜鳥講到爛了,我就不多說了,下面給出基本操作的 假定原陣列為a 1.n 樹狀陣列b 1.n 考慮靈活性的需要,使用int a傳陣列。define lowbit x x x int sum int a,int x void update int a,int x,int...
樹狀陣列總結
樹狀陣列是對乙個陣列改變某個元素和求和比較實用的資料結構。兩中操作都是o logn 在解題過程中,我們有時需要維護乙個陣列的字首和s i a 1 a 2 a i 但是不難發現,如果我們修改了任意乙個a i s i s i 1 s n 都會發生變化。可以說,每次修改a i 後,調整字首和s在最壞情況下...
樹狀陣列總結
今天學習了一下樹狀陣列,做乙個簡單總結。樹狀陣列可分為兩種操作,1 修改單個點,統計區間和 一般為 向上修改 update1 向下統計 sum1 2 修改區間,統計單個點 一般為向下修改 update2 向上統計 sum2 主要模板如下 int c n int lowbit int x 用於確定區間...