给出一棵树,有两种操作:
询问 [u,v] 的最大权值
然后更改第 i 条边的权值为 val
这是树链剖分的入门题,昨天调试了半天才做出这题,我还是太弱了。>但是还是弄懂了什么是树链剖分
树链剖分有先要进行两次dfs操作进行初始化。
第一个初始化操作,求得是每个节点的开头fa[u],每个节点的深度deep[u],以及每个节点的重儿子son[u]。
第二个初始化操作,求得是重链的头top[u],以及在每个节点在线段树中的位置id[u]。
为什么树链剖分会更快?
因为每次询问的时候,查询的点都是跳到重链的头,这样类似一个跳表,这样减少了中间访问的次数怎么询问[u,v]的最值?
(1) 记 tp1=top[u] , tp2=top[v] 。
(2) 当 tp1!=tp2 时:不妨设 dep[tp1]>=dep[tp2] ,那么就更新u到tp1的父边的权值( log(n) ),并使 u=fa[tp1] 。
(3) 当 tp1=tp2 时:u与v在同一条重链上,若u与v不是同一点,就更新u到v路径上的边的权值( log(n) ),否则修改完成。查询的时候用线段树维护的是,当前点u,在线段树中的位置 id[u] ,以及重链的头tp1,在线段树中的位置 id[tp1] ,查询的就是区间就是 [id[u],id[tp1]]
my code
#include
#include
#include
#include
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
const int N = 10005;
struct Edge {
int u, v, val;
Edge() {}
Edge(int u, int v, int val) : u(u), v(v), val(val) {}
} edge[N];
int n;
vector<int> G[N];
int deep[N], size[N], fa[N], id[N], son[N], top[N];
int dfs_clock;
void init() {
for(int i = 0; i <= n; i++) G[i].clear();
}
void addEdge(int u, int v) {
G[u].push_back(v);
}
void dfs1(int u, int pre, int de) {
deep[u] = de;
size[u] = 1;
son[u] = 0;
fa[u] = pre;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(pre == v) continue;
dfs1(v, u, de+1);
if(size[son[u]] < size[v])
son[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp;
id[u] = ++dfs_clock;
if(son[u]) dfs2(son[u], tp);
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int maxv[N<<2];
inline void pushUp(int o) {
maxv[o] = max(maxv[ls], maxv[rs]);
}
void build(int o, int L, int R) {
maxv[o] = 0;
if(L == R) return ;
int M = (L + R)/2;
build(lson);
build(rson);
pushUp(o);
}
void modify(int o, int L, int R, int pos, int val) {
if(L == R) {
maxv[o] = val;
return ;
}
int M = (L + R)/2;
if(pos <= M) modify(lson, pos, val);
else modify(rson, pos, val);
pushUp(o);
}
int query(int o, int L, int R, int ql, int qr) {
if(ql <= L && R <= qr) return maxv[o];
int M = (L + R)/2, ret = 0;
if(ql <= M) ret = max(ret, query(lson, ql, qr));
if(qr > M) ret = max(ret, query(rson, ql, qr));
return ret;
}
int find(int u, int v) {
int tp1 = top[u], tp2 = top[v];
int ans = 0;
while(tp1 != tp2) {
if(deep[tp1] < deep[tp2]) {
swap(tp1, tp2);
swap(u, v);
}
ans = max(ans, query(1, 1, dfs_clock, id[tp1], id[u]));
u = fa[tp1];
tp1 = top[u];
}
if(u == v) return ans;
if(deep[u] > deep[v]) swap(u, v);
return max(ans, query(1, 1, dfs_clock, id[son[u]], id[v]));
}
int main() {
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
init();
int u, v, val;
for(int i = 1; i < n; i++) {
scanf("%d%d%d", &u, &v, &val);
edge[i] = Edge(u, v, val);
addEdge(u, v);
addEdge(v, u);
}
dfs_clock = 0;
dfs1(1, 0, 1);
dfs2(1, 1);
build(1, 1, dfs_clock);
for(int i = 1; i < n; i++) {
if(deep[edge[i].v] < deep[edge[i].u])
swap(edge[i].v, edge[i].u);
modify(1, 1, dfs_clock, id[edge[i].v], edge[i].val);
}
char oper[10];
while(~scanf("%s", oper)) {
if(oper[0] == 'D') break;
if(oper[0] == 'Q') {
scanf("%d%d", &u, &v);
printf("%d\n", find(u, v));
}else if(oper[0] == 'C') {
scanf("%d%d", &u, &val);
modify(1, 1, dfs_clock, id[edge[u].v], val);
}
}
}
return 0;
}