# 树上方法总结 LCA 树上倍增 树链剖分 树的直径 重心

382人阅读 评论(55)

- 倍增
- 树链剖分
- dfs
- 树的直径和重心
- 树形dp
- 树上背包
- 树上期望dp
- 各种图转树

### dfs

dfs用于统计很多信息。这里贴一份常用代码。

void dfs(int u, int pa) {
siz[u] = 1;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i].to;
if(v == pa) continue;
fa[v] = u;
dpt[v] = dpt[u] + 1;
w[v] = G[u][i].dist;
//g[u].push_back(v); 如果想把无根树转成有根树可以加这一句
dfs(v, u);
siz[u] += siz[v];
}
}

### 倍增

void getanc() {
for(int i = 0; i < n; i++) anc[i][0] = fa[i];
for(int j = 1; (1<<j) < n; j++) for(int i = 0; i < n; i++) anc[i][j] = anc[anc[i][j-1]][j-1];
}

int lca(int x, int y) {
if(dpt[x] < dpt[y]) swap(x, y);
for(int j = 30; j >= 0; j--) if(dpt[x] - (1<<j) >= dpt[y]) x = anc[x][j];
if(x == y) return x;
for(int j = 30; j >= 0; j--) if(anc[x][j] != anc[y][j]) {
x = anc[x][j];
y = anc[y][j];
}
return anc[x][0];
}

### 树链剖分

#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const long long maxn = 100050;
vector<long long> G[maxn];
long long n, p;
long long fa[maxn], hson[maxn], tp[maxn], dpt[maxn], w[maxn], siz[maxn]; //hson是重儿子 tp是每条链的顶端 dpt是深度 w是点权 siz是子树大小
long long id[maxn], idn, real[maxn];
struct despac {
long long l, r, su, laz;
}tr[maxn<<2]; //线段树节点
long long nn;
long long a = 0, c = getchar(), w = 1;
for(; c < '0' || c > '9'; c = getchar()) if(c == '-') w = -1;
for(; c >= '0' && c <= '9'; c = getchar()) a = a * 10 + c - '0';
return a * w;
}

void build(long long u, long long pa) {
long long maxw = 0;
siz[u] = 1;
for(long long i = 0; i < G[u].size(); i++) {
long long v = G[u][i];
if(v == pa) continue;
fa[v] = u;
dpt[v] = dpt[u] + 1;
build(v, u);
if(siz[v] > maxw) {
maxw = siz[v];
hson[u] = v;
}
siz[u] += siz[v];
}
}
void build2(long long u, long long pa, long long top) {
real[idn] = u;
id[u] = idn++;
tp[u] = top;
if(hson[u] != -1) build2(hson[u], u, tp[u]);
for(long long i = 0; i < G[u].size(); i++) {
long long v = G[u][i];
if(v == pa || v == hson[u]) continue;
build2(v, u, v);
}
}

void build_st(long long x, long long l, long long r) {
if(l == r) {
tr[x].su = w[real[l]];
tr[x].su %= p;
return;
}
long long mid = l + r >> 1;
build_st(tr[x].l=nn++, l, mid);
build_st(tr[x].r=nn++, mid+1, r);
tr[x].su = tr[tr[x].l].su + tr[tr[x].r].su;
tr[x].su %= p;
}
void pushdown(long long x, long long ln, long long rn) {
if(tr[x].laz) {
tr[tr[x].l].laz += tr[x].laz;
tr[tr[x].l].laz %= p;
tr[tr[x].r].laz += tr[x].laz;
tr[tr[x].r].laz %= p;
tr[tr[x].l].su += ln * tr[x].laz;
tr[tr[x].l].su %= p;
tr[tr[x].r].su += rn * tr[x].laz;
tr[tr[x].r].su %= p;
tr[x].laz = 0;
}
}
long long query(long long x, long long l, long long r, long long L, long long R) {
if(L <= l && R >= r) return tr[x].su;
long long mid = l+r>>1;
pushdown(x, mid-l+1, r-mid);
long long ans = 0;
if(L <= mid) {
ans += query(tr[x].l, l, mid, L, R);
ans %= p;
}
if(R > mid) {
ans += query(tr[x].r, mid+1, r, L, R);
ans %= p;
}
return ans;
}
void modify(long long x, long long l, long long r, long long L, long long R, long long val) {
if(L <= l && R >= r) {
tr[x].su += val * (r-l+1);
tr[x].su %= p;
tr[x].laz += val;
tr[x].laz %= p;
return;
}
long long mid = l+r>>1;
pushdown(x, mid-l+1, r-mid);
if(L <= mid) modify(tr[x].l, l, mid, L, R, val);
if(R > mid) modify(tr[x].r, mid+1, r, L, R, val);
tr[x].su = tr[tr[x].l].su + tr[tr[x].r].su;
tr[x].su %= p;
}

long long cquery(long long x, long long y) { // c = chain
long long tx = tp[x], ty = tp[y];
long long ans = 0;
while(tx != ty) {   // not in one chain
if(dpt[tx] < dpt[ty]) {
swap(tx, ty);
swap(x, y);
}
ans += query(0, 0, n-1, id[tx], id[x]);
ans %= p;
x = fa[tx];
tx = tp[x];
}
if(dpt[x] < dpt[y]) swap(x, y);
ans += query(0, 0, n-1, id[y], id[x]);
ans %= p;
return ans;
}
long long cmodify(long long x, long long y, long long val) {
long long tx = tp[x], ty = tp[y];
while(tx != ty) {
if(dpt[tx] < dpt[ty]) {
swap(tx, ty);
swap(x, y);
}
modify(0, 0, n-1, id[tx], id[x], val);
x = fa[tx];
tx = tp[x];
}
if(dpt[x] < dpt[y]) swap(x, y);
modify(0, 0, n-1, id[y], id[x], val);
}

int main() {
long long q, rt;
for(long long i = 0; i < n; i++) w[i] = read();
for(long long i = 0; i < n-1; i++) {
G[from].push_back(to);
G[to].push_back(from);
}
memset(hson, -1, sizeof(hson));
build(rt, -1);
build2(rt, -1, rt);
build_st(nn++, 0, n-1);
while(q--) {
if(op == 1) { //链修改
cmodify(x, y, z);
}
if(op == 2) { //链询问
printf("%lld\n", cquery(x, y));
}
if(op == 3) { //子树修改（整个子树增加z ）
modify(0, 0, n-1, id[x], id[x]+siz[x]-1, z);
}
if(op == 4) { //子树询问
printf("%lld\n", query(0, 0, n-1, id[x], id[x]+siz[x]-1));
}
}
return 0;
}

### tarjan思路

别人
aziint Dangxingyu Joker Azreal_Death call_me_std
dj vanilla ldy wsyzh
个人资料
等级：
访问量： 4778
积分： 407
排名： 12万+
最新评论