poj2763: Housewife Wind

题目链接
裸树链剖分。要求维护一棵树,支持修改某条树边的长度以及查询两点间距离。
闲话少叙,直接上代码。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 100010;

struct edge {
	int v, w, id, nxt;
}lib[N<<1];//据说std::vector会TLE
int mapHead[N], mapTot = 0;

inline void ins(int u, int v, int w, int id) {
	lib[mapTot] = (edge) {v, w, id, mapHead[u]};
	mapHead[u] = mapTot++;
}

int size[N], dep[N], son[N], fa[N], top[N], seg[N], tn[N], segCnt;
int pos[N], val[N];

void dfs1(int u, int f) {
	fa[u] = f; size[u] = 1; dep[u] = dep[f] + 1;
	for (int i = mapHead[u]; i != -1; i = lib[i].nxt) {
		int &v = lib[i].v, &w = lib[i].w, &id = lib[i].id;
		if (v == f) continue;
		dfs1(v, u);
		if (size[son[u]] < size[v])
			son[u] = v;
		size[u] += size[v];
		val[pos[id] = v] = w;
	}
}

void dfs2(int u, int tp) {
	top[u] = tp; seg[u] = ++segCnt, tn[seg[u]] = u;
	if (! son[u]) return;
	dfs2(son[u], tp);
	for (int i = mapHead[u]; i != -1; i = lib[i].nxt) {
		int &v = lib[i].v;
		if (v == fa[u] || v == son[u]) continue;
		dfs2(v, v);
	}
}

int tree[N<<1];
#define g(l, r) (l + r | l != r)
#define o g(l, r)
#define ls g(l, mid)
#define rs g(mid + 1, r)
int gl, gr, gx;
#define set(l, r, x) gl = l, gr = r, gx = x;

inline void update(int l, int r) {
	int mid = l + r >> 1;
	tree[o] = tree[ls] + tree[rs];
}

void buildTree(int l, int r) {
	if (l == r) {
		tree[o] = val[tn[l]];
		return;
	}
	int mid = l + r >> 1;
	buildTree(l, mid);
	buildTree(mid + 1, r);
	update(l, r);
}

int n, q, s;

void query(int l, int r) {
	if (gl <= l && r <= gr) {
		gx += tree[o]; return;
	}
	int mid = l + r >> 1;
	if (gl <= mid) query(l, mid);
	if (mid + 1 <= gr) query(mid + 1, r);
}

inline void Query(int u, int v) {
	int f1 = top[u], f2 = top[v]; gx = 0;
	while (f1 != f2) {
		if (dep[f1] < dep[f2]) {
			swap(u, v); swap(f1, f2);
		}
		set(seg[f1], seg[u], gx); query(1, n);
		u = fa[f1]; f1 = top[u];
	}
	if (dep[u] < dep[v]) swap(u, v);
	set(seg[v], seg[u], gx); query(1, n);
	printf("%d\n", gx - val[v]);
}

void modify(int l, int r) {
	if (l == r) {
		tree[o] = gx;
		return;
	}
	int mid = l + r >> 1;
	if (gl <= mid) modify(l, mid);
	else modify(mid + 1, r);
	update(l, r);
}

inline void Modify(int x, int w) {
	set(x, x, w);
	modify(1, n);
}

int main() {
	cin >> n >> q >> s;
	memset(mapHead, 0xff, sizeof(mapHead));
	for (int i = 1; i < n; i++) {
		int u, v, w; scanf("%d%d%d", &u, &v, &w);
		ins(u, v, w, i); ins(v, u, w, i);
	}
	dfs1(1, 0);
	dfs2(1, 1);
	buildTree(1, n);
	while (q--) {
		int t, x; scanf("%d%d", &t, &x);
		if (t == 0) {
			Query(x, s); s = x;
		} else {
			int w; scanf("%d", &w);
			Modify(seg[pos[x]], w);
			val[pos[x]] = w;
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值