1 2 3 4

树链剖分模板题

我感觉就是线段树+LCA的思想了

核心还是线段树

 

需要注意

在标记中,一个节点的所有子孙一定都是标号小于该节点的。

 

https://www.luogu.com.cn/problem/P2590

洛谷例题

解答

功能变多了就会很长很长

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;

vector<int>G[maxn];

int n;
void add(int x, int y) {
	G[x].push_back(y);
}
int dep[maxn], top[maxn], id[maxn], fa[maxn], siz[maxn];

int son[maxn];

ll list[maxn];//初始编号
ll cns[maxn];//改动后用来建线段树的编号

ll sum[4 * maxn];//求和
ll mx[4 * maxn];

int dfs1(int x, int f,int d) {
	dep[x] = d;
	fa[x] = f;
	siz[x] = 1;
	int s = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int p = G[x][i];
		if (p == f) continue;
		dfs1(p, x, d + 1);
		siz[x] += siz[p];
		if (s < siz[p]) {
			s = siz[p];
			son[x] = p;
		}
	}
	return 0;
}//haah
int cnt;
int dfs2(int x,int t) {
	id[x] = ++cnt;
	cns[cnt] = list[x];
	top[x] = t;
	if (!son[x]) return 0;
	dfs2(son[x], t);//重儿子重复利用t

	for (int i = 0; i < G[x].size();i++) {
		int p = G[x][i];
		if (p == fa[x] || p == son[x]) continue;
		dfs2(p, p);//轻儿子新建t
	}
	return 0;
}

int bulit(int node, int be, int en) {
	if (be == en) {
		mx[node] = cns[be];
		sum[node] = cns[be];
		return 0;
	}
	int l = node * 2;
	int r = node * 2 + 1;

	int mid = (be + en) / 2;
	bulit(l, be, mid);
	bulit(r, mid + 1, en);
	sum[node] = sum[l] + sum[r];
	mx[node] = max(mx[l], mx[r]);
	return 0;
}

int update(int node, int be, int en, int i, int val) {
	if (be == en) {
		sum[node] = val;
		mx[node] = val;
		return 0;
	}
	int l = node * 2;
	int r = node * 2 + 1;
	int mid = (be + en) / 2;

	if (i <= mid) update(l, be, mid, i, val);
	else update(r, mid + 1, en, i, val);

	sum[node] = sum[l] + sum[r];
	mx[node] = max(mx[l], mx[r]);

	return 0;
}
ll qurry_sum(int node, int be, int en, int LL, int RR) {
	if (LL > en || RR < be) return 0;
	if (LL <= be && RR >= en) {
		return sum[node];
	}
	int l = node * 2;
	int r = node * 2 + 1;
	int mid = (be + en) / 2;
	ll val1 = qurry_sum(l, be, mid, LL, RR);
	ll val2 = qurry_sum(r, mid + 1, en, LL, RR);
	return val1 + val2;
}

ll qurry_max(int node, int be, int en, int LL, int RR) {
	if (LL > en || RR < be) return -1e10;
	
	if (LL <= be && en <= RR) {
		return mx[node];
	}
	int l = node * 2;
	int r = node * 2 + 1;
	int mid = (be + en) / 2;
	ll val1 = qurry_max(l, be, mid, LL, RR);
	ll val2 = qurry_max(r, mid + 1, en, LL, RR);
	return max(val1, val2);
}


ll qrank_max(int x, int y) {
	ll ans = -1e18;
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		ll cns = qurry_max(1, 1, n, id[top[x]], id[x]);
		ans = max(ans, cns);
		x = fa[top[x]];
	}
	//现在两个点在一个重链上了
	if (dep[x] > dep[y]) swap(x, y);
	//x现在在y上面,id更小
	ll cns = qurry_max(1, 1, n, id[x], id[y]);//注意顺序
	ans = max(ans, cns);
	return ans;
}


ll qrank_sum(int x, int y) {
	ll ans = 0;
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		ll cns = qurry_sum(1, 1, n, id[top[x]], id[x]);
		ans += cns;
		x = fa[top[x]];
	}
	//现在两个点在一个重链上了
	if (dep[x] > dep[y]) swap(x, y);
	//x现在在y上面,id更小
	ll cns = qurry_sum(1, 1, n, id[x], id[y]);//注意顺序
	ans += cns;
	return ans;
}


char op[20];


int main() {
	scanf("%d", &n);
	for (int i = 1; i < n; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		add(x, y);
		add(y, x);
	}
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &list[i]);
	}

	dfs1(1, -1, 0);
	dfs2(1, 1);
	bulit(1, 1, n);
	
	int q;
	scanf("%d", &q);
	while (q--) {
		int x, y;
		scanf("%s", op);
		scanf("%d %d", &x, &y);
		ll ans = 0;

		if (op[1] == 'H') {
			update(1, 1, n, id[x], y);
		}
		else if (op[1] == 'M') {
			ans = qrank_max(x, y);
			printf("%lld\n", ans);
		}
		else if (op[1] == 'S') {
			ans = qrank_sum(x, y);
			printf("%lld\n", ans);
		}

	}
	return 0;
}

  

posted @ 2020-02-29 19:16  Lesning  阅读(120)  评论(0编辑  收藏  举报