如題,已知一棵包含 nn 個結點的樹(連通且無環),每個節點上包含乙個數值,需要支援以下操作:
操作 11: 格式: 1\ x\ y\ z1xyz 表示將樹從 xx 到 yy 結點最短路徑上所有節點的值都加上 zz。
操作 22: 格式: 2\ x\ y2xy 表示求樹從 xx 到 yy 結點最短路徑上所有節點的值之和。
操作 33: 格式: 3\ x\ z3xz 表示將以 xx 為根節點的子樹內所有節點值都加上 zz。
操作 44: 格式: 4\ x4x 表示求以 xx 為根節點的子樹內所有節點值之和
#includeusingnamespace
std;
const
int maxn=1e6+100
;typedef
long
long
ll;int
n,m,r,mod;
vector
g[maxn];
int son[maxn];//
重兒子編號
int id[maxn];//
新編號int fa[maxn];//
父親節點
intcnt;
intdep[maxn];
int size[maxn];//
子樹大小
int top[maxn];//
當前鏈頂節點
int w[maxn];//
初始點權陣列
intwt[maxn];
//線段樹部分
struct
node segtree[maxn*4
];void build (int i,int l,int
r)
int mid=(l+r)>>1
; build(i
<<1
,l,mid);
build(i
<<1|1,mid+1
,r);
segtree[i].sum=segtree[i<<1].sum+segtree[i<<1|1
].sum;
segtree[i].sum%=mod;
}void spread (int
i) }
void update (int i,int l,int r,int
val)
spread(i);
int mid=(segtree[i].l+segtree[i].r)>>1
;
if (l<=mid)
update(i
<<1
,l,r,val);
if (r>mid)
update(i
<<1|1
,l,r,val);
segtree[i].sum=segtree[i<<1].sum+segtree[i<<1|1
].sum;
segtree[i].sum%=mod;
}ll query (
int i,int l,int
r) //
樹剖部分
int qrange (int x,int
y)
if (dep[x]>dep[y]) swap(x,y);
ans+=query(1
,id[x],id[y]);
return ans%mod;
} void uprange (int x,int y,int
k)
if (dep[x]>dep[y]) swap(x,y);
update(
1,id[x],id[y],k);
}int qson (int
x) int upson (int x,int
k)
int lca (int x,int
y)
void dfs1 (int x,int f,int
deep)
}void dfs2 (int x,int
topf)
}int
main ()
dfs1(r,
0,1);
dfs2(r,r);
build(
1,1,n);
while (m--)
}
P3384 模板 輕重鏈剖分(樹鏈剖分模板)
入口 題目描述 如題,已知一棵包含 nn 個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作 11 格式 1 x y z1 x y z 表示將樹從 xx 到 yy 結點最短路徑上所有節點的值都加上 zz。操作 22 格式 2 x y2 x y 表示求樹從 xx 到 yy 結點最短...
洛谷 P3384 模板 輕重鏈剖分(樹鏈剖分)
簡單點說,就是把一棵樹變成多條鏈。這裡說的是重鏈剖分。在遍歷一顆樹的時候,我們強制從父親節點走向兒子時,先走所有兒子中以兒子為根的子樹最大的那個兒子。其他的兒子不管什麼順序都可。這樣就可以把dfs序作為鏈。例如上面這棵樹,邊上的藍色數字就是遍歷順序。說一些定義 重邊 父親結點和重兒子連成的邊 輕邊 ...
樹鏈剖分 P3384 模板 樹鏈剖分
題目描述 戳這裡 題解 其實樹剖的重點就在於輕重鏈,這篇文章寫的很好 然而我線段樹寫得全是問題,改了半天2333 如下 include include include using namespace std const int maxn 100005 int n,m,root,tt,tot,lnk ...