题意:给一棵树,树的边上是有权值的。
输入给n-1条边,有两种操作:
- CHANGE i j 将第i条边的权值改为j
- QUERY i j 询问节点i到节点j路径上的权值最大值
思路:
- 树链剖分处理出每条链,放到数组中,使用线段树来维护。
- 因为是边上的权值,所以将其转为点上的权值,转变为深度较大的点上的权值。
- 使用线段树是因为它支持动态查询区间最值和单点修改。
写错了的几次是因为对于使用点上的权值,所以处理同一条链上的最大值的时候,例如 u -> v 的链时,要查询的时u+1 -> v的最大值。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <stack>
#include <string>
#include <math.h>
#include <bitset>
#include <ctype.h>
#define CLR(n,b) memset(n, b, sizeof(n))
using namespace std;
typedef pair<int,int> P;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-9;
const int N = 2e4 + 5;
const int mod = 1e9 + 7;
struct Edge
{
int u,v,w;
Edge() {}
Edge(int a, int b, int c): u(a), v(b), w(c) {}
};
int fa[N],son[N], p[N],fp[N], top[N],dep[N],sz[N];
int a[N];
int pos;
int n,m,k;
vector<Edge> edges;
vector<int> G[N];
void init(int n)
{
CLR(fa, 0); CLR(son, -1); CLR(p, -1); CLR(a, 0);
CLR(fp, -1); CLR(top, 0); CLR(sz, 0); CLR(dep, 0);
pos = 0; edges.clear();
for(int i = 0; i <= n; i++) G[i].clear();
}
void addedge(int u, int v, int w)
{
edges.push_back(Edge(u,v,w));
edges.push_back(Edge(v,u,w));
int m = edges.size();
G[u].push_back(m-2);
G[v].push_back(m-1);
}
void dfs(int u, int pre, int d)
{
fa[u] = pre;
dep[u] = d;
sz[u] = 1;
son[u] = -1;
for(int i = 0; i < G[u].size(); i++)
{
Edge &e = edges[G[u][i]];
int v = e.v;
if(v == pre) continue;
dfs(v, u, d+1);
a[v] = e.w;
sz[u] += sz[v];
if(son[u] == -1 || sz[son[u]] < sz[v])
son[u] = v;
}
}
void getpos(int u, int sp)
{
top[u] = sp;
p[u] = ++pos;
fp[p[u]] = u;
if(son[u] == -1) return;
getpos(son[u], sp);
for(int i = 0; i < G[u].size(); i++)
{
Edge &e = edges[G[u][i]];
int v = e.v;
if(v == son[u] || v == fa[u]) continue;
getpos(v, v);
}
}
int Max[N<<2];
void build(int rt, int l, int r)
{
if(l == r)
{
Max[rt] = -INF;
return;
}
int mid = l+r >> 1;
build(rt << 1, l, mid);
build(rt << 1 |1, mid+1, r);
Max[rt] = max(Max[rt<<1], Max[rt<<1|1]);
}
void update(int pos, int val, int rt, int l, int r)
{
if(pos < l || pos > r) return;
int mid = l+r >> 1;
if(l == r)
{
Max[rt] = val;
return;
}
if(pos > mid) update(pos, val, rt << 1 | 1, mid+1, r);
else update(pos, val, rt << 1, l, mid);
Max[rt] = max(Max[rt<<1], Max[rt<<1|1]);
}
int query(int L, int R, int rt, int l, int r)
{
if(L <= l && r <= R) return Max[rt];
int mid = l+r >> 1;
int ans = 0;
if(mid >= L) ans = max(ans, query(L, R, rt<<1, l, mid));
if(mid < R) ans = max(ans, query(L, R, rt<<1|1, mid+1, r));
return ans;
}
int Query(int u, int v)
{
int f1 = top[u], f2 = top[v];
int ans = 0;
while(f1 != f2)
{
if(dep[f1] < dep[f2])
{
swap(f1, f2);
swap(u, v);
}
ans = max(ans, query(p[f1], p[u], 1, 1, n));
u = fa[f1];
f1 = top[u];
}
if(u == v) return ans;
if(dep[u] > dep[v]) swap(u, v);
/**WA**/
ans = max(ans, query(p[u]+1, p[v], 1, 1, n));
/****/
return ans;
}
int t;
int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
init(n);
for(int i = 0; i < n-1; i++)
{
int u,v,w;
scanf("%d%d%d", &u, &v, &w);
addedge(u,v,w);
}
dfs(1,1,0);
getpos(1,1);
build(1,1,n);
for(int i = 1; i <= n; i++)
update(p[i], a[i], 1, 1, n);
while(true)
{
char cmd[10];
int x,y;
scanf("%s", cmd);
if(cmd[0] == 'D') break;
scanf("%d%d", &x,&y);
if(cmd[0] == 'Q')
printf("%d
", Query(x,y));
else
{
int u = edges[x*2-2].u, v = edges[x*2-2].v;
if(dep[u] < dep[v]) swap(u,v);
update(p[u], y, 1, 1, n);
}
}
}
return 0;
}