看了一下題解裡的zkw線段樹,感覺講的不是很清楚啊(可能有清楚的但是我沒翻到,望大佬勿怪)。
決定自己寫一篇。。。希望大家能看明白。。。
zkw線段樹是一種優秀的非遞迴線段樹,速度比普通線段樹快兩道三倍,同時**量不大。
(當然,存在很多線段樹可做zkw不可做的題)
zkw線段樹的核心思路就是先修改葉子,然後從底向上沿著路徑修改。
如果畫一張圖出來整個過程有點像逐漸兩條交回在根節點的鏈。
注意:對於需要維護的區間$[1,n]$,zkw線段樹維護的實際上是$[0,n+1]$。
建樹
1 inline voidbuild(ll n)
bit表示的底層的大小,我們需要先預處理出這個全域性變數。
然後我們就可以先把葉子的值全部讀入。
讀入之後就順著葉子向上走,更新上面的節點。
這一段**沒有什麼複雜的地方。
更新
1 inline voidupdate(ll l,ll r,ll val)
8for(;s;s>>=1,t>>=1)tree[s]+=val*ln,tree[t]+=val*rn;
9 }
更新操作稍微比建樹複雜一點。
s和t就是先前提到的兩條鏈,當然準確地說,它們的軌跡才是那兩條鏈。
ln,rn表示的是當前節點的長度(也就是s,t的長度)。
x表示的是s和t中間這一坨的長度。
然後也是一樣的自底向上,每一次先更新兩邊,然後再判斷該更新左兒子還是右兒子。
查詢
1inline ll query(ll l,ll r)
9for(;s;s>>=1,t>>=1)ans+=tag[s]*ln,ans+=tag[t]*rn;
10return
ans;
11 }
查詢操作和更新一樣,沒什麼好講的。
不開o2跑了511ms,比普通線段樹的760+ms快很多(可能是我寫醜了)
完整**如下:
1 #include2using
namespace
std;
3 typedef unsigned long
long
ll;4
const ll n=100100;5
ll n,m;
6ll op,x,y,z;
7ll a[n];
8ll bit;
9 ll tree[n<<2],tag[n<<2
];10 inline void
build(ll n)
16 inline void
update(ll l,ll r,ll val)
23for(;s;s>>=1,t>>=1)tree[s]+=val*ln,tree[t]+=val*rn;24}
25inline ll query(ll l,ll r)
33for(;s;s>>=1,t>>=1)ans+=tag[s]*ln,ans+=tag[t]*rn;
34return
ans;35}
36int
main()
45 }
題解 P3372 模板 線段樹 1
題目 剛剛學了樹狀陣列的區間加法和區間求和操作,就用來水掉這題了 本篇適合學會樹狀陣列的人群 前置芝士 普通樹狀陣列 差分樹狀陣列 學過樹狀陣列的人都知道,我們對於乙個陣列,進行處理後,就可以在 o log n 的時間內進行單點修改和區間求和 假設對於陣列 a n 我們用樹狀陣列的方法處理後,就可以...
P3372 模板 線段樹 1
線段樹學習 這個題來看,線段樹分為建樹,更新,查詢。1.建樹 void build ll p,ll l,ll r ll mid l r 1 build lson p l,mid build rson p mid 1,r push up sum p void push up sum ll p 這段 的...
P3372 模板 線段樹 1
題 include includeusing namespace std typedef long long ll ll n,m,ans,x,y,op,val 因為下面有的函式需要用到x,y,val值,懶得傳參,故直接寫為全域性變數 const int n 100000 struct nodetre...