树链剖分就是将一个树的路径转化成重链和轻链,对其节点或者边就行编号,从而可以转化成其他的数据结构问题来解决问题。树链剖分有些类似莫队,也就是相当于把树的路径进行了分块。
数组的含义:
fa[]每个节点的父节点
num[]每个节点子节点的个数(包含自己)
son[v]与v在同一重链的重儿子
top[v]节点v所在链的顶端节点(v可以是一个单独的点,相当于自己组成一条重链)
pos[v]节点v编号后在线段树中的编号
pre[v]v节点之前的编号
deep[v]节点v在树中的深度(根深度为1)
修改或者查询时:
对于[u,v]区间,f1=top[u],f2=top[v],ql,qr分别为左右端点
有两种情况(deep[f1]>deep[f2]):
f1!=f2: ql=pos[top[u]],qr=pos[u],再更新u=fa[top[u]]
f1==f2: ql=pos[u],qr=pos[v] (deep[u] < deep[v])
重复循环上面的过程,ql,qr就是需要查询和修改的左右区间
【HYSBZ - 1036 树的统计】
这个题是裸的树剖加线段树
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 1e5 + 5;
struct node {
int l, r, maxx, sum;
}tree[maxn<<2];
int pos[maxn], pre[maxn], value[maxn], son[maxn], num[maxn], top[maxn], deep[maxn],fa[maxn];
int n, tot, q;
vector<int>e[maxn];
void dfs1(int u,int f,int dep)
{
deep[u] = dep;
num[u] = 1;
fa[u] = f;
for (int i = 0; i < e[u].size(); i++) {
int v = e[u][i];
if (v == fa[u]) continue;
dfs1(v, u, dep + 1);
num[u] += num[v];
if (num[v] > num[son[u]])
son[u] = v;
}
}
void dfs2(int u,int tp)
{
pos[u] = ++tot; pre[pos[u]] = u;
top[u] = tp;
if (son[u]) dfs2(son[u], tp);
for (int i = 0; i < e[u].size(); i++) {
int v = e[u][i];
if (v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
inline void pushup(int rt)
{
tree[rt].maxx = max(tree[rt << 1].maxx, tree[rt << 1 | 1].maxx);
tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
}
void build(int l, int r, int rt)
{
tree[rt].l = l; tree[rt].r = r;
if (l == r) {
tree[rt].maxx = tree[rt].sum = value[pre[l]];
return;
}
int mid = l + r >> 1;
build(l, mid, rt << 1);
build(mid + 1, r, rt << 1 | 1);
pushup(rt);
}
void update(int pos, int rt, int val)
{
if (tree[rt].l == tree[rt].r) {
tree[rt].sum = tree[rt].maxx = val;
return;
}
int mid = tree[rt].l + tree[rt].r >> 1;
if (pos <= mid) update(pos, rt << 1, val);
else if (pos > mid) update(pos, rt << 1 | 1, val);
pushup(rt);
}
pair<int, int> query(int l, int r, int rt)
{
pair<int, int>ret;
if (l == tree[rt].l&&r == tree[rt].r) {
ret.first = tree[rt].maxx;
ret.second = tree[rt].sum;
return ret;
}
int mid = tree[rt].l + tree[rt].r >> 1;
if (r <= mid) return query(l, r, rt << 1);
else if (l > mid) return query(l, r, rt << 1 | 1);
else {
pair<int, int>a, b;
a = query(l, mid, rt << 1);
b = query(mid + 1, r, rt << 1 | 1);
ret.first = max(a.first, b.first);
ret.second = a.second + b.second;
return ret;
}
pushup(rt);
}
int getsum(int u, int v)
{
int f1 = top[u], f2 = top[v], ret = 0;
while (f1 != f2) {
if (deep[f1] < deep[f2]) {
swap(f1, f2); swap(u, v);
}
ret += query(pos[top[u]], pos[u], 1).second;
u = fa[f1]; f1 = top[u];
}
if (deep[u] < deep[v]) swap(u, v);
ret += query(pos[v], pos[u], 1).second;
return ret;
}
int getmax(int u, int v)
{
int f1 = top[u], f2 = top[v], ret = -0x3f3f3f3f;
while (f1 != f2) {
if (deep[f1] < deep[f2]) {
swap(f1, f2); swap(u, v);
}
ret =max(ret, query(pos[top[u]], pos[u], 1).first);
u = fa[f1]; f1 = top[u];
}
if (deep[u] < deep[v]) swap(u, v);
ret = max(ret, query(pos[v], pos[u], 1).first);
return ret;
}
int main()
{
scanf("%d",&n);
for (int i = 1; i < n; i++) {
int a, b;
scanf("%d%d",&a,&b);
e[a].push_back(b);
e[b].push_back(a);
}
for (int i = 1; i <= n; i++) scanf("%d",&value[i]);
dfs1(1, 1, 1);
dfs2(1, 1);
build(1, tot, 1);
scanf("%d",&q);
for (int i=1 ; i <= q; i++) {
char op[10];
int u, v;
scanf("%s%d%d",op,&u,&v);
if (strcmp(op, "QSUM") == 0) {
printf("%d\n",getsum(u,v));
}
else if (strcmp(op, "QMAX") == 0) {
printf("%d\n", getmax(u, v));
}
else {
update(pos[u], 1, v);
}
}
return 0;
}