寫**又犯了很sb的錯誤,線段樹寫錯了。。。
好像每次都會把r-l+1寫成l-r+1,然後就只有20分。。。
**寫的比較醜,壓了壓之後190行。。。
基本上是我打過的最長的乙個模板了
然後簡單介紹一下樹剖吧。。。
樹鏈剖分,就是把樹剖分成鏈,然後用資料結構來維護這些鏈,使得詢問、修改的複雜度達到o(
logn
) o(l
ogn)
(不會證明。。。)
幾個定義:
這樣我們就可以利用這個性質來把樹上的修改、查詢問題轉化成區間問題,就可以用樹狀陣列、線段樹等資料結構來維護,進行修改、查詢等操作
當然其中也包含lca問題,這裡並不是用倍增求的lca,而是用剖分好的鏈來求的
好像這樣剖分時間複雜度會比較***,但是我並不會證明。。。好弱啊。。。
還有一些小細節問題,可以看**
我是看這裡學的樹剖:
#include
#include
#include
#include
#include
#define for(i,l,r) for(int i=l;i<=r;++i)
#define mid ((l+r)>>1)
#define ls (x<<1)
#define rs ((x<<1)|1)
#define maxn 100010
using namespace std;
inline int
read()
while(isdigit(c))
return a*(t?-1:1);
}struct edgee[maxn*2];
int n,m,root,p,cnt;
int v[maxn],last[maxn],fa[maxn],dep[maxn],tid[maxn],dfs[maxn],son[maxn],top[maxn],size[maxn];
int lazy[maxn*4],sum[maxn*4],ans;
void dfs1(int now,int fat,int depth)
temp=e[temp].next;
}}void dfs2(int now,int t)
}void build(int l,int r,int
x) else
}void down(int l,int r,int
x)void modify(int l,int r,int
x,int ll,int rr,int k)
else
}void ask(int l,int r,int
x,int ll,int rr)//線段樹詢問
else
}void query(int
x,int
y)//
else
}if(dfs[x]<=dfs[y])ask(1,n,1,dfs[x],dfs[y]);
else ask(1,n,1,dfs[y],dfs[x]);
printf("%d\n",ans);
}void update(int
x,int
y,int z)
else
}if(dfs[x]<=dfs[y])
modify(1,n,1,dfs[x],dfs[y],z);
else
modify(1,n,1,dfs[y],dfs[x],z);
}void add(int from,int to)
int main()
dfs1(root,0,1);cnt=0;dfs2(root,root);build(1,n,1);
for(i,1,m)
else
if(tx==2)
else
if(tx==3)
else
}return
0;}
樹鏈剖分學習筆記
樹鏈剖分 mod estc oder modestcoder modest code r如果你是重兒子,你就在重路徑上。如果你是輕兒子,暴力沿著祖先向上爬最多log nlogn logn 次就可以遇到重路徑。或者到根 而樹上操作基本就是找祖先 也許有人喜歡我的碼風 include include d...
樹鏈剖分學習筆記
前言 書上只講了重鏈剖分,菜雞也只會這一種,想看其他的是別想了。要會樹鏈剖分,首先你需要了解一些概念。我們把乙個節點的所有兒子節點中子樹節點數最大的稱為重兒子,也就是size最大的子節點。size的定義我在講換根dp時說過,因此不再贅述。對於每個節點的重兒子,我們用 son x 來記錄它,父親節點到...
樹鏈剖分 學習筆記
前置知識 dfs 序,線段樹 我們可以回顧兩個問題 1.樹上從 s 到 t 的路徑,每個點權值加上 z 很簡單。遍歷整棵樹即可。2.求樹上 s 到 t 的權值和。lca 可做。可以利用 lca 的性質 dis s dis t 2 dis lca 做即可。時間複雜度 o n log n 但是把這兩個問...