#include<bits/stdc++.h>
#define ls (rt << 1) // 左儿子
#define rs (rt << 1 | 1) // 右儿子
using namespace std;
const int N = 1e5 + 5; // 最大节点数
const int M = 2e5 + 5; // 最大边数(无向边*2)
// 查询类型常量
const int QUERY_SUM = 0; // 区间和
const int QUERY_MAX = 1; // 区间最大值
const int QUERY_MIN = 2; // 区间最小值
// 操作类型常量
const int OP_ADD = 0; // 区间加操作
const int OP_SET = 1; // 区间覆盖操作
// 前向星结构体
struct edge {
int to; // 边的终点
int nxt; // 下一条边
} e[M];
// 基本变量
int n, root; // 节点数, 根节点
int tim; // 时间戳,用于DFS序
int head[N]; // 前向星头数组
int tot; // 边计数器
// 树链剖分数组
int fa[N]; // fa[x]: 节点x的父亲
int dep[N]; // dep[x]: 节点x的深度
int siz[N]; // siz[x]: 节点x的子树大小
int son[N]; // son[x]: 节点x的重儿子
int top[N]; // top[x]: 节点x所在重链的顶部结点
int dfn[N]; // dfn[x]: 节点x的DFS序
int rnk[N]; // rnk[x]: DFS序x对应的节点编号
// 原树节点权值
int val[N]; // val[x]: 节点x的原始权值
// 线段树部分
struct SegTree {
int sum; // 区间和
int max; // 区间最大值
int min; // 区间最小值
int lazy; // 懒标记(区间加)
int set_tag; // 覆盖标记 (区间覆盖)
bool has_set; // 是否有覆盖标记
} seg[N << 2];
namespace TreeDecomposition {
// ========== 前向星部分 ==========
// 添加边
void adde(int u, int v) {
e[++tot].to = v;
e[tot].nxt = head[u];
head[u] = tot;
}
// 添加无向边
void plus_adde(int u, int v) {
adde(u, v);
adde(v, u);
}
// ========== 线段树部分 ==========
// 合并子节点信息
void pushup(int rt) {
seg[rt].sum = seg[ls].sum + seg[rs].sum;
seg[rt].max = max(seg[ls].max, seg[rs].max);
seg[rt].min = min(seg[ls].min, seg[rs].min);
}
// 下传懒标记
void pushdown(int rt, int l, int r) {
int mid = (l + r) >> 1;
// 优先处理覆盖标记
if (seg[rt].has_set) {
int set_val = seg[rt].set_tag;
int lenL = mid - l + 1;
int lenR = r - mid;
// 更新左子树
seg[ls].sum = set_val * lenL;
seg[ls].max = seg[ls].min = set_val;
seg[ls].lazy = 0; // 覆盖操作清空加标记
seg[ls].set_tag = set_val;
seg[ls].has_set = true;
// 更新右子树
seg[rs].sum = set_val * lenR;
seg[rs].max = seg[rs].min = set_val;
seg[rs].lazy = 0; // 覆盖操作清空加标记
seg[rs].set_tag = set_val;
seg[rs].has_set = true;
seg[rt].has_set = false;
seg[rt].set_tag = 0;
}
// 再处理加标记
if (seg[rt].lazy != 0) {
int lazy = seg[rt].lazy;
int lenL = mid - l + 1;
int lenR = r - mid;
// 更新左子树
seg[ls].sum += lazy * lenL;
seg[ls].max += lazy;
seg[ls].min += lazy;
seg[ls].lazy += lazy;
// 更新右子树
seg[rs].sum += lazy * lenR;
seg[rs].max += lazy;
seg[rs].min += lazy;
seg[rs].lazy += lazy;
seg[rt].lazy = 0;
}
}
// 构建线段树
void buildSegTree(int rt, int l, int r) {
seg[rt].lazy = 0;
seg[rt].has_set = false;
if (l == r) {
int node = rnk[l]; // 通过rnk找到对应节点
seg[rt].sum = seg[rt].max = seg[rt].min = val[node];
return;
}
int mid = (l + r) >> 1;
buildSegTree(ls, l, mid);
buildSegTree(rs, mid + 1, r);
pushup(rt);
}
// 统一更新函数
void updateSeg(int rt, int l, int r, int L, int R, int add_val, int set_val, int op_type) {
if (L <= l && r <= R) {
if (op_type == OP_SET) { // 区间覆盖
seg[rt].sum = set_val * (r - l + 1);
seg[rt].max = seg[rt].min = set_val;
seg[rt].set_tag = set_val;
seg[rt].has_set = true;
seg[rt].lazy = 0; // 覆盖操作清空加标记
} else { // 区间加
seg[rt].sum += add_val * (r - l + 1);
seg[rt].max += add_val;
seg[rt].min += add_val;
seg[rt].lazy += add_val;
}
return;
}
pushdown(rt, l, r);
int mid = (l + r) >> 1;
if (L <= mid) updateSeg(ls, l, mid, L, R, add_val, set_val, op_type);
if (R > mid) updateSeg(rs, mid + 1, r, L, R, add_val, set_val, op_type);
pushup(rt);
}
// 区间查询
int querySeg(int rt, int l, int r, int L, int R, int type) {
if (L <= l && r <= R) {
if (type == QUERY_SUM) return seg[rt].sum;
else if (type == QUERY_MAX) return seg[rt].max;
else return seg[rt].min;
}
pushdown(rt, l, r);
int mid = (l + r) >> 1;
if (type == QUERY_SUM) {
int res = 0;
if (L <= mid) res += querySeg(ls, l, mid, L, R, type);
if (R > mid) res += querySeg(rs, mid + 1, r, L, R, type);
return res;
} else if (type == QUERY_MAX) {
int res = INT_MIN;
if (L <= mid) res = max(res, querySeg(ls, l, mid, L, R, type));
if (R > mid) res = max(res, querySeg(rs, mid + 1, r, L, R, type));
return res;
} else { // QUERY_MIN
int res = INT_MAX;
if (L <= mid) res = min(res, querySeg(ls, l, mid, L, R, type));
if (R > mid) res = min(res, querySeg(rs, mid + 1, r, L, R, type));
return res;
}
}
// ========== 树链剖分部分 ==========
// 初始化
void init(int _n, int _root = 1) {
n = _n;
root = _root;
tot = 0;
tim = 0;
memset(head, 0, sizeof(head));
memset(son, 0, sizeof(son));
memset(val, 0, sizeof(val));
}
// 设置节点原始权值
void setVal(int u, int value) {
val[u] = value;
}
// 第一次DFS:预处理父亲、深度、子树大小、重儿子
void dfs1(int u, int f) {//u为当前节点,f父亲
fa[u] = f;//标记每个点的父亲
dep[u] = dep[f] + 1;//标记每个点的深度
siz[u] = 1;//标记每个非叶子节点的子树大小(记自己)
son[u] = 0;//记录重儿子的儿子数
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == f) continue;//若为父亲则continue
dfs1(v, u);//dfs其儿子
siz[u] += siz[v];//把它的儿子数加到它身上
if (siz[v] > siz[son[u]]) {
son[u] = v;//标记每个非叶子节点的重儿子编号
}
}
}
// 第二次DFS:预处理DFS序、重链顶端
void dfs2(int u, int t) {
top[u] = t;
dfn[u] = ++tim;
rnk[tim] = u; // 记录DFS序到节点的映射
// 优先遍历重儿子,保证重链上的DFS序连续
if (son[u]) {
dfs2(son[u], t);
}
// 遍历轻儿子
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == fa[u] || v == son[u]) continue;//等于父亲或自己都不行
dfs2(v, v); // 轻儿子作为新重链的顶端
}
}
// 构建树链剖分
void build() {
tim = 0;
dfs1(root, 0);
dfs2(root, root);
buildSegTree(1, 1, n); // 构建线段树
}
}
namespace Debug{
// 获取查询接口
int getFa(int x) { return fa[x]; }
int getDep(int x) { return dep[x]; }
int getSiz(int x) { return siz[x]; }
int getSon(int x) { return son[x]; }
int getTop(int x) { return top[x]; }
int getDfn(int x) { return dfn[x]; }
int getRnk(int x) { return rnk[x]; }
// 打印信息(调试用)
void debug() {
cout << "节点信息:" << endl;
cout << "id\tfa\tdep\tsiz\tson\ttop\tdfn\tval" << endl;
for (int i = 1; i <= n; i++) {
cout << i << "\t" << fa[i] << "\t" << dep[i] << "\t"
<< siz[i] << "\t" << son[i] << "\t" << top[i]
<< "\t" << dfn[i] << "\t" << val[i] << endl;
}
}
}
namespace funtion{
// ========== 树链剖分 + 线段树操作 ==========
// 查询LCA(最近公共祖先)
int lca(int u, int v) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
u = fa[top[u]];
}
return dep[u] < dep[v] ? u : v;
}
// 路径修改:u到v路径上所有节点加val
void updatePathAdd(int u, int v, int val) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
TreeDecomposition::updateSeg(1, 1, n, dfn[top[u]], dfn[u], val, 0, OP_ADD);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
TreeDecomposition::updateSeg(1, 1, n, dfn[u], dfn[v], val, 0, OP_ADD);
}
// 路径修改:u到v路径上所有节点设置为val(覆盖)
void updatePathSet(int u, int v, int val) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
TreeDecomposition::updateSeg(1, 1, n, dfn[top[u]], dfn[u], 0, val, OP_SET);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
TreeDecomposition::updateSeg(1, 1, n, dfn[u], dfn[v], 0, val, OP_SET);
}
// 路径查询:查询u到v路径上指定类型的信息
int queryPath(int u, int v, int type) {
int res;
if (type == QUERY_SUM) res = 0;
else if (type == QUERY_MAX) res = INT_MIN;
else res = INT_MAX;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
int cur = TreeDecomposition::querySeg(1, 1, n, dfn[top[u]], dfn[u], type);
if (type == QUERY_SUM) res += cur;
else if (type == QUERY_MAX) res = max(res, cur);
else res = min(res, cur);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
int cur = TreeDecomposition::querySeg(1, 1, n, dfn[u], dfn[v], type);
if (type == QUERY_SUM) res += cur;
else if (type == QUERY_MAX) res = max(res, cur);
else res = min(res, cur);
return res;
}
// 子树修改:以u为根的子树所有节点加val
void updateSubtreeAdd(int u, int val) {
int l = dfn[u], r = dfn[u] + siz[u] - 1;
TreeDecomposition::updateSeg(1, 1, n, l, r, val, 0, OP_ADD);
}
// 子树修改:以u为根的子树所有节点设置为val
void updateSubtreeSet(int u, int val) {
int l = dfn[u], r = dfn[u] + siz[u] - 1;
TreeDecomposition::updateSeg(1, 1, n, l, r, 0, val, OP_SET);
}
// 子树查询:查询以u为根的子树指定类型的信息
int querySubtree(int u, int type) {
int l = dfn[u], r = dfn[u] + siz[u] - 1;
return TreeDecomposition::querySeg(1, 1, n, l, r, type);
}
// 单点修改:节点u加val
void updateNodeAdd(int u, int val) {
TreeDecomposition::updateSeg(1, 1, n, dfn[u], dfn[u], val, 0, OP_ADD);
}
// 单点修改:节点u设置为val(覆盖)
void updateNodeSet(int u, int val) {
TreeDecomposition::updateSeg(1, 1, n, dfn[u], dfn[u], 0, val, OP_SET);
}
// 单点查询
int queryNode(int u, int type) {
return TreeDecomposition::querySeg(1, 1, n, dfn[u], dfn[u], type);
}
}
using namespace TreeDecomposition;
using namespace funtion;
using namespace Debug;
// void task();
int main(){
cin.tie(0)->sync_with_stdio(0);
task();
return 0;
}
// 使用示例
void task() {
int n = 8; // 节点数
init(n, 1); // 初始化,根节点为1
// 构建一棵树(示例)
plus_adde(1, 2);
plus_adde(1, 3);
plus_adde(2, 4);
plus_adde(2, 5);
plus_adde(3, 6);
plus_adde(5, 7);
plus_adde(6, 8);
// 设置节点权值
for (int i = 1; i <= n; i++) {
setVal(i, i); // 初始权值等于节点编号
}
// 构建树链剖分(包含线段树)
build();
// 调试输出
debug();
// 查询示例
cout << "\n=== 初始查询 ===" << endl;
cout << "路径1-7的和: " << queryPath(1, 7, QUERY_SUM) << endl;
cout << "路径1-7的最大值: " << queryPath(1, 7, QUERY_MAX) << endl;
cout << "路径1-7的最小值: " << queryPath(1, 7, QUERY_MIN) << endl;
// 测试区间加操作
cout << "\n=== 测试区间加操作 ===" << endl;
cout << "路径2-6所有节点加10" << endl;
updatePathAdd(2, 6, 10);
cout << "路径2-6的和(加10后): " << queryPath(2, 6, QUERY_SUM) << endl;
cout << "路径2-6的最大值(加10后): " << queryPath(2, 6, QUERY_MAX) << endl;
// 测试覆盖操作
cout << "\n=== 测试覆盖操作 ===" << endl;
cout << "路径3-8所有节点设置为100" << endl;
updatePathSet(3, 8, 100);
cout << "路径3-8的和(覆盖后): " << queryPath(3, 8, QUERY_SUM) << endl;
cout << "路径3-8的最小值(覆盖后): " << queryPath(3, 8, QUERY_MIN) << endl;
// 测试混合操作(覆盖后加)
cout << "\n=== 测试混合操作 ===" << endl;
cout << "节点2的子树设置为50" << endl;
updateSubtreeSet(2, 50);
cout << "节点2的子树和(设置后): " << querySubtree(2, QUERY_SUM) << endl;
cout << "节点2的子树加20" << endl;
updateSubtreeAdd(2, 20);
cout << "节点2的子树和(再加20后): " << querySubtree(2, QUERY_SUM) << endl;
// 测试单点操作
cout << "\n=== 测试单点操作 ===" << endl;
cout << "节点4设置为200" << endl;
updateNodeSet(4, 200);
cout << "节点4的值: " << queryNode(4, QUERY_SUM) << endl;
cout << "节点4加30" << endl;
updateNodeAdd(4, 30);
cout << "节点4的值(加30后): " << queryNode(4, QUERY_SUM) << endl;
// 查询LCA
cout << "\n=== LCA查询 ===" << endl;
cout << "LCA(4, 7) = " << lca(4, 7) << endl;
cout << "LCA(8, 7) = " << lca(8, 7) << endl;
// 验证懒标记正确性
cout << "\n=== 验证懒标记正确性 ===" << endl;
cout << "最终路径1-7的和: " << queryPath(1, 7, QUERY_SUM) << endl;
cout << "最终路径1-7的最大值: " << queryPath(1, 7, QUERY_MAX) << endl;
cout << "最终路径1-7的最小值: " << queryPath(1, 7, QUERY_MIN) << endl;
return ;
}