樹鏈剖分 時間!!!!
首先要學會線段樹。由於線段樹是基本技能,所以不再此過多解釋。
樹鏈剖分操作如下
操作1: 格式: 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z
操作2: 格式: 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和
操作3: 格式: 3 x z 表示將以x為根節點的子樹內所有節點值都加上z
操作4: 格式: 4 x 表示求以x為根節點的子樹內所有節點值之和
還有幾個概念:重兒子,輕兒子,重鏈,輕鏈。
眾所周知,以每乙個節點為根節點下所成的樹(語文技能崩潰)都有乙個大小(節點的數量)
如果有乙個兒子體型(節點數)在所有兄弟姐妹中最大,那麼這個兒子就是這個節點的重兒子;
其他的兒子都是輕兒子。
重邊就是每兩個重兒子之間的邊(手拉手,我們都是重兒子);輕邊就是剩下的;
重鏈就是相鄰的每個重邊連起來的鏈,包括一條端點重兒子和輕兒子之間的邊,也就是所有重鏈以乙個輕兒子開始;
看完定義該幹事了!!!
首先,處理dep,fa,siz,son
void dfs1(int u,intfa)}
second 新編,賦值,找頭,先重再輕
因為先處理重兒子就會讓重兒子之間的編號是連續的。
void dfs2(int u,inttp)
}
third 套用線段樹。
**:
#include#include#include
using
namespace
std;
const
int maxn=100050
;int
n,m,s,mo,a[maxn];
int pre[maxn*2],other[maxn*2
],last[maxn],l;
intf[maxn],siz[maxn],dep[maxn],son[maxn];
intid[maxn],cnt,top[maxn],b[maxn];
void add(int x,int
y)//
下面是線段樹
struct
tree
t[4*maxn];//
四倍,前人的經驗
void build(int x,int l,int r)//
建樹
int mid=(l+r)>>1
; build(
2*x,l,mid);
build(
2*x+1,mid+1
,r);
t[x].sum=(t[2*x].sum+t[2*x+1].sum)%mo;
}void update(int x)//
更新懶標籤
void change(int x,int l,int r,int z)//
改變值
if(t[x].lazy) update(x);
int mid=(t[x].l+t[x].r)>>1
;
if(r<=mid) change(2*x,l,r,z);
else
if(l>mid) change(2*x+1
,l,r,z);
else
t[x].sum=(t[2*x].sum+t[2*x+1].sum)%mo;
}int query(int x,int l,int r)//
查詢區間和
if(t[x].lazy) update(x);
int mid=(t[x].l+t[x].r)>>1
;
if(r<=mid) return query(2*x,l,r);
else
if(l>mid) return query(2*x+1
,l,r);
else}//
上面是線段樹
void dfs1(int u,int
fa)}
void dfs2(int u,int
tp)
}void tchange(int x,int y,int
z)//
到一條鏈上之後跳出
if(dep[x]>dep[y]) swap(x,y);//
找到深度淺的那個
change(1,id[x],id[y],z);//
最後一條鏈加z
}int tcha(int x,int
y)
if(dep[x]>dep[y]) swap(x,y);
ans+=query(1
,id[x],id[y]);
ans%=mo;
return
ans;
}void changeson(int x,int
z)int chason(int
x)int
main()
for(int i=1;i)
dfs1(s,0);
dfs2(s,s);
build(
1,1,n);
for(int i=1;i<=m;i++)
else
if(op==2
)
else
if(op==3
)
else
if(op==4
)
}return0;
}
剛學會,理解還是不太到位,歡迎指正。
P3384 模板 樹鏈剖分
傳送門 題目描述 如題,已知一棵包含n個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作1 格式 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z 操作2 格式 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和 操作3 格式 3 x z 表示將以x為根...
P3384 模板 樹鏈剖分
p3384 模板 樹鏈剖分 樹鏈剖分是把一棵樹劃分成幾條鏈,這幾條鏈又能組成陣列,然後把陣列建成線段樹,繼而相當於在樹樹上操作。include include include include include using namespace std const int maxn 2e5 10 int ...
P3384 模板 樹鏈剖分
題目描述 如題,已知一棵包含n個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作1 格式 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z 操作2 格式 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和 操作3 格式 3 x z 表示將以x為根節點的子...