對於一棵樹上兩個節點所構成的鏈的操作,我們可以用樹鏈剖分,來將樹轉化為多條鏈的集合(線性結構),從而將樹上鏈的結構轉化為線性結構的區間操作.
找出每個節點的重兒子(包含節點最多的兒子)
重兒子優先輸出dfs序
對於如下一棵樹進行剖分
找出其重兒子(紅色線)
每個節點與其重兒子遞迴組成一條鏈(葉子節點沒有重兒子)
樹鏈剖分後的序列為: \(0,1,2,6,3,5,4\)
現在要修改兩個點路徑上所有點的權值,假如兩個點在一條鏈上,就直接修改序列的區間.否則就修改從當前點到鏈根的區間,然後跳到鏈根的父親遞迴修改.
比如現在要修改\(4到5\)的所有點的權值
所以對於樹鏈剖分序的區間修改(dfs序的下標)為: 7-7,5-6,1-2
#include#define ll long long
#define for(i,l,r) for(int i = l ; i <= r ;++i )
#define inf 0x3f3f3f3f
#define eps (1e-9)
#define all(t) t.begin(),t.end()
#define lson(i) i<<1
#define rson(i) (i<<1|1)
using namespace std;
const int maxn =30010;
struct edgeedge[maxn*2];
int head[maxn],tot; //前向星
int top[maxn]; // 所在重鏈的頂端節點
int fa[maxn]; // 父親
int deep[maxn]; // 深度
int num[maxn]; // 子節點個數
int p[maxn]; // 在dfs序的位置
int fp[maxn]; // 位置節點號的反向對映
int son[maxn]; // 重兒子
int pos; // dfs序當前下標
// 加邊
void addedge(int u,int v)
// 初始化
void init()
//第一遍dfs 處理fa,num,deep,son
void dfs1(int u,int pre,int d)
}}// 第二遍dfs 處理 top,p,fp
void dfs2(int u,int sp)
}// 原陣列
int a[maxn];
struct nodeseg[maxn*4];
// 線段樹操作
void push_up(int p)
void build(int pp,int l,int r)
int mid = (l+r)>>1;
build(lson(pp),l,mid);
build(rson(pp),mid+1,r);
push_up(pp);
}void update(int p,int l,int r,int val)
int mid = (seg[p].r+seg[p].l)>>1;
if(l<=mid) update(lson(p),l,r,val);
if(r>mid) update(rson(p),l,r,val);
push_up(p);
}int qmax(int p,int l,int r)
int res = -inf;
int mid = (seg[p].r+seg[p].l)>>1;
if(l<=mid) res = max(res,qmax(lson(p),l,r));
if(r>mid) res = max(res,qmax(rson(p),l,r));
return res;
}int qsum(int p,int l,int r)
int res = 0;
int mid = (seg[p].r+seg[p].l)>>1;
if(l<=mid) res = res+qsum(lson(p),l,r);
if(r>mid) res = res+qsum(rson(p),l,r);
return res;
}// 查詢和
int fsum(int u,int v)
res+= qsum(1,p[tu],p[u]);
u = fa[tu];
tu = top[u];
}if(deep[u] > deep[v]) swap(u,v);
res += qsum(1,p[u],p[v]);
return res;
}// 查詢最大
int fmax(int u,int v)
res=max(res,qmax(1,p[tu],p[u]));// 查詢u節點到他的鏈頂
u = fa[tu]; // 跳到鏈頂的父節點
tu = top[u];// 更新鏈頂
}if(deep[u] > deep[v]) swap(u,v);
res = max(res,qmax(1,p[u],p[v]));// 同一條鏈 直接區間查詢
return res;
}int n;
int main()
dfs1(1,0,0);
dfs2(1,1);
for(i,1,n)
// for(i,1,n)cout << endl;
build(1,1,n);
// for(i,1,n)
int q;
char op[10];
scanf("%d",&q);
for(i,1,q)else if(op[1]=='m')else if(op[1]=='s')
}return 0;
}
題目連 BZOJ 1036 樹的統計 Count 樹鏈剖分
題目大意 一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作 i.change u t 把結點u的權值改為t ii.qmax u v 詢問從點u到點v的路徑上的節點的最大權值 iii.qsum u v 詢問從點u到點v的路徑上的節點的權值和 ...
樹鏈剖分 線段樹 bzoj1036 樹的統計
一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作 i.change u t 把結點u的權值改為t ii.qmax u v 詢問從點u到點v的路徑上的節點的最大權值 iii.qsum u v 詢問從點u到點v的路徑上的節點的權值和 注意 從點...
bzoj1036 樹的統計 樹鏈剖分 LCT
ac通道 題解 看到題目,發現是樹剖一眼題,所以就秒掉了。include include include include include include includeusing namespace std typedef long long ll define file read define m...