题目大意:
给你一棵n个节点的树,实现以下两种查询:
1.CHANGE i ti : 将第i条边的权值更改为ti
2.QUERY a b : 询问节点a到节点b路径上最大的边权
树链剖分的水题,树链剖分详见:传送门
这里注意由于存在更改操作,需要增加一个数组map[i]表示第i条边在线段树中的位置。
代码如下:
/*
ID: Sunshine_cfbsl
PROG: SPOJ00375
LANG: C++
*/
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
const int MAXN = 10010, INF = 1000000000;
vector<int> G[MAXN];
int n, e, W[MAXN][MAXN], No[MAXN][MAXN], map[MAXN];
int fa[MAXN], dep[MAXN], son[MAXN], w[MAXN], top[MAXN], size[MAXN];
class Segment_Tree {
private:
int t[MAXN*4];
public:
void clear() {
memset(t, 0, sizeof(t));
}
void update(int p, int l, int r, int x, int v) {
if(l == r) {
t[p] = v;
return;
}
int mid = (l+r)>>1;
if(x <= mid) update(p<<1, l, mid, x, v);
else update(p<<1|1, mid+1, r, x, v);
t[p] = max(t[p<<1], t[p<<1|1]);
}
int query(int p, int l, int r, int x, int y) {
if(l==x && r==y) return t[p];
int mid = (l+r)>>1;
if(y <= mid) return query(p<<1, l, mid, x, y);
else if(x > mid) return query(p<<1|1, mid+1, r, x, y);
else return max(query(p<<1, l, mid, x, mid), query(p<<1|1, mid+1, r, mid+1, y));
}
}tree;
void dfs1(int p) {
int i;
size[p] = 1;
for(i = 0; i < (int)G[p].size(); i++) {
if(dep[G[p][i]] != -1) continue;
fa[G[p][i]] = p;
dep[G[p][i]] = dep[p]+1;
dfs1(G[p][i]);
size[p] += size[G[p][i]];
if(son[p]==-1 || size[G[p][i]]>size[son[p]]) son[p] = G[p][i];
}
}
void dfs2(int p) {
int i;
if(son[p] != -1) {
top[son[p]] = top[p];
w[son[p]] = ++e;
map[No[p][son[p]]] = e;
tree.update(1, 1, n-1, e, W[p][son[p]]);
dfs2(son[p]);
}
for(i = 0; i < (int)G[p].size(); i++) {
if(G[p][i]==son[p] || G[p][i]==fa[p]) continue;
top[G[p][i]] = G[p][i];
w[G[p][i]] = ++e;
map[No[p][G[p][i]]] = e;
tree.update(1, 1, n-1, e, W[p][G[p][i]]);
dfs2(G[p][i]);
}
}
int query(int u, int v) {
int res = 0;
int f1 = top[u], f2 = top[v];
while(f1 != f2) {
if(dep[f1] < dep[f2]) {
swap(f1, f2);
swap(u, v);
}
res = max(res, tree.query(1, 1, n-1, w[f1], w[u]));
u = fa[f1];
f1 = top[u];
}
if(dep[u] > dep[v]) swap(u, v);
if(u != v) res = max(res, tree.query(1, 1, n-1, w[son[u]], w[v]));
return res;
}
int main() {
int i, t, a, b, c;
scanf("%d", &t);
while(t--) {
tree.clear();
for(i = 1; i <= n; i++) G[i].clear();
memset(fa, -1, sizeof(fa));
memset(son, -1, sizeof(son));
memset(dep, -1, sizeof(dep));
e = 0;
scanf("%d", &n);
for(i = 1; i < n; i++) {
scanf("%d%d%d", &a, &b, &c);
G[a].push_back(b);
G[b].push_back(a);
W[a][b] = W[b][a] = c;
No[a][b] = No[b][a] = i;
}
dep[1] = 0;
top[1] = 1;
dfs1(1);
dfs2(1);
char tmp[20];
scanf("%s", tmp);
while(tmp[0] != 'D') {
scanf("%d%d", &a, &b);
if(tmp[0] == 'Q') printf("%d\n", query(a, b));
else tree.update(1, 1, n-1, map[a], b);
scanf("%s", tmp);
}
}
return 0;
}
空间时间还行吧,由于是第一次写树链剖分,代码比较详细,没有去刻意地去缩短。