[ SPOJ - QTREE]Query on a tree && 树链剖分

本文介绍了一种高效的数据结构——重链分解,并结合线段树实现路径上的查询和更新操作。通过构建重链分解,可以将树状结构转换为链状结构,从而利用线段树快速解决树上路径问题。文章详细展示了算法的具体实现过程,包括如何建立边、进行DFS遍历、获取节点ID、构建线段树等步骤,并提供了一个完整的示例程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<iostream>
#define SF scanf
#define PF printf
#define ls (i<<1)
#define rs (i<<1|1)
using namespace std;
typedef long long LL;
const int MAXN = 10000;
const int INF = 0x3f3f3f3f;
int n;
char s[10];
// Build Edge

struct node {
	int v;
	node *next;
} Edge[MAXN*3+10], *ecnt = &Edge[0], *adj[MAXN+10];
inline void addedge(int u, int v) {
	node *p = ++ecnt;
	p->v = v;
	p->next = adj[u];
	adj[u] = p;
}
inline void add(int u, int v) { 
	addedge(u, v); addedge(v, u);
} 

// DFS
int F[MAXN+10], son[MAXN+10], idx[MAXN+10], L[MAXN+10];
int sz[MAXN+10], top[MAXN+10]; // top 重链头 idx(x到x父亲边的编号)
int dfn;
void dfs(int u, int fa, int lev) {
	son[u] = 0; F[u] = fa; L[u] = lev; sz[u] = 1;
	for(node *p = adj[u]; p; p = p->next) {
		int v = p->v;
		if(v == fa) continue;
		dfs(v, u, lev+1);
		sz[u] += sz[v];
		if(sz[v] > sz[son[u]]) son[u] = v;
	}
}
void Getid(int u, int tp) {
	idx[u] = ++dfn; top[u] = tp;
	if(son[u]) Getid(son[u], top[u]);
	for(node *p = adj[u]; p; p = p->next) {
		int v = p->v;
		if(v == F[u] || v == son[u]) continue;
		Getid(v, v);
	}
}
// Seg Tree

struct Seg_Tree {
	int MAX[(MAXN<<2)+10], VAL[(MAXN<<2)+10];
	int L[(MAXN<<2)+10], R[(MAXN<<2)+10], Mid[(MAXN<<2)+10];
	void build(int i, int l, int r) {
		VAL[i] = MAX[i] = -INF;
		L[i] = l; R[i] = r;
		if(l == r) return ;
		int mid = Mid[i] = l + (r-l) / 2;
		build(ls, l, mid);
		build(rs, mid+1, r);
	}
	void ins(int i, int x, int val) {
		if(L[i] == R[i]) {
			VAL[i] = MAX[i] = val;
			return ;
		}
		int mid = Mid[i];
		if(x <= mid) ins(ls, x, val);
		else ins(rs, x, val);
		MAX[i] = max(MAX[ls], MAX[rs]);
	}
	int query(int i, int l, int r) {
		if(l <= L[i] && R[i] <= r) return MAX[i];
		int mid = Mid[i], ret = -INF;
		if(l <= mid) ret = max(ret, query(ls, l, r));
		if(r > mid) ret = max(ret, query(rs, l, r));
		return ret;
	}
} seg;
// LCA
inline int find(int x, int y) {
	int ans = -INF;
	while(top[x] != top[y]) {
		if(L[top[x]] < L[top[y]]) swap(x, y);
		ans = max(ans, seg.query(1, idx[top[x]], idx[x]));
		x = F[top[x]];
	}
	if(L[x] > L[y]) swap(x, y);
	if(x != y) ans = max(ans, seg.query(1, idx[x]+1, idx[y]));
	return ans;
}
// Main
int E[MAXN+10][3];
int main()
{
	int _T; SF("%d", &_T); while(_T--) {
		dfn = 0; ecnt = &Edge[0]; memset(adj, 0, sizeof(adj));
		SF("%d", &n);
		for(int i = 1; i < n; i++) {
			SF("%d%d%d", &E[i][0], &E[i][1], &E[i][2]);
			add(E[i][0], E[i][1]);
		}
		dfs(1, 1, 1);
		Getid(1, 1);
		seg.build(1, 2, n);
		for(int i = 1; i < n; i++) {
			if(L[E[i][0]] > L[E[i][1]]) swap(E[i][0], E[i][1]);
			seg.ins(1, idx[E[i][1]], E[i][2]);
		}
		while(SF("%s", s)) {
			if(s[0] == 'D') break;
			else if(s[0] == 'C') {
				int x, val; SF("%d%d", &x, &val);
				seg.ins(1, idx[E[x][1]], val);
			}
			else {
				int x, y; SF("%d%d", &x, &y);
				PF("%d\n", find(x, y));
			}
		}
		puts("");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值