樹鏈剖分:
對於每個結點 連線子節點多的那個子樹的邊叫做重邊
重邊連起來成鏈 叫重鏈 (不止是只有一條重鏈)
使用線段樹或者其他的資料結構存重鏈 用此資料結構進行操作
兩個dfs操作
: 第乙個dfs 求出重鏈 深度dep陣列 父節點fa陣列 和每個結點的子結點個數size陣列 知道了size才可以求出重鏈
第二個dfs 連線重鏈 對於每個重鏈 重鏈的標號為第乙個結點的編號 belong陣列表示每個結點的所在重鏈編號
在第二個dfs中記錄dfs序 這樣才可以形成連續的區間! 後面的操作都是pos[x] 而不是x因為在樹中的第x個不一定是資料結構中的第x個
基礎題目 bzoj4034樹上操作
#include#include#include#include#include#include#define ll long long
#define n 200005
using namespace std;
int b[n],p[n],nt[n],fa[n],belong[n],cover[n],pos[n],v[n],sz[n];
ll sum[2*n],tag[2*n];
int n,m,cnt,num;
int read()
while(ch>='0'&&ch<='9')
return x*f;
}void dfs(int x) }}
void dfs2(int x,int idno)
if(k>0)
for(int e=p[x];e;e=nt[e]) }}
void pushdown(int l,int r,int k)
void add(int k,int l,int r,int x,int y,ll val)
int mid=(l+r)>>1;
if(x<=mid) add(k<<1,l,mid,x,min(mid,y),val);
if(y>mid) add(k<<1|1,mid+1,r,max(mid+1,x),y,val);
sum[k]=sum[k<<1]+sum[k<<1|1];
}void insert(int x,int y)
ll query(int k,int l,int r,int x,int y)
ll querysum(int x)
s+=query(1,1,n,1,pos[x]);
return s;
}int main()
dfs(1);
dfs2(1,1);
for(int i=1;i<=n;i++)
add(1,1,n,pos[i],pos[i],v[i]);
int t,x,a;
while(m--)
if(t==2)
if(t==3) printf("%lld\n",querysum(x));
} return 0;
}
筆記 樹鏈剖分
洛谷 樹鏈剖分模板 前置芝士 鏈式前向星,線段樹,dfs序 這裡寫的是重鏈剖分。參考部落格指盜圖 x正義小學生x 樹鏈剖分可以把一棵樹 投影 到乙個序列上,然後用線段樹維護一些東西。通過重兒子的性質來保證時間複雜度。我們首先使用兩次dfs進行預處理,將樹投影到序列上。對於乙個有兒子的節點,我們定義它...
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...
樹鏈剖分筆記 (戳)
對於樹鏈剖分,看到大佬紛紛各種躺切內心很是惶恐,於是跪著請教大佬之後把自己的一點感悟發出來以防以後忘了qwq 指一種對樹進行劃分的演算法,它先通過輕重邊剖分將樹分為多條鏈,保證每個點屬於且只屬於一條鏈,然後再通過資料結構 樹狀陣列 sbt splay 線段樹等 來維護每一條鏈 常見的剖分的方法是輕重...