树链剖分

练习地址:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#overview

以下为我的AC代码

A

树链剖分+线段树区间更新求单点值

//@ScratchingBear g++

#include <cstdio>
#include <vector>
#include <cstring>
#define maxn 100010


using namespace std;

int link[maxn], tot;
int dep[maxn], fa[maxn], son[maxn], siz[maxn], top[maxn], w[maxn];
vector<int>edg[maxn];

void dfs1(int u){
	siz[u] = 1; son[u] = 0;
	for(int i=0;i<edg[u].size();i++)if(edg[u][i] != fa[u]){
		fa[edg[u][i]] = u;
		dep[edg[u][i]] = dep[u] + 1;
		dfs1(edg[u][i]);
		if(siz[edg[u][i]] > siz[son[u]]) 
			son[u] = edg[u][i];
		siz[u] += siz[edg[u][i]];
	}
}


void dfs2(int u, int tp){
	top[u] = tp;
	w[u] = ++tot;
	link[tot] = u;
	if(son[u] == 0) return ;
	dfs2(son[u], tp);
	for(int i=0;i<edg[u].size();i++) 
		if(edg[u][i] != son[u] && edg[u][i] != fa[u]){
			dfs2(edg[u][i], edg[u][i]);
		}
}

			//以上为树链剖分部分

struct Node{
	int l, r;
	int sum;
};
Node tree[maxn * 4];
int num[maxn];

void build_tree(int id, int l, int r){
	tree[id].l = l;
	tree[id].r = r;
	tree[id].sum = 0;
	if(l != r){
		int mid = (l + r) / 2;
		build_tree(id * 2, l, mid);
		build_tree(id * 2 + 1, mid + 1,  r);
	}
}

void update(int id, int l, int r, int val){
	if(tree[id].l >= l && tree[id].r <= r) {
		tree[id].sum += val;
		return ;
	}
	if(tree[id].l > r || tree[id].r < l) return ;
	update(id * 2, l, r, val);
	update(id * 2 + 1, l, r, val);
}

int ask(int id, int pos){
	int ans = 0;
	while(true){
		ans += tree[id].sum;
		if(tree[id].l == tree[id].r) break;
		int mid = (tree[id].l + tree[id].r) / 2;
		if(pos <= mid) id *= 2;
		else id = id * 2 + 1;

	}
	// you know ....
	return ans + num[link[pos]];
}

void add_val(int x, int y, int val){	//熟练剖分的具体使用
	while(top[x] != top[y]){
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		update(1, w[top[x]], w[x], val);
		x = fa[top[x]];
	}
	if(w[x] > w[y]) swap(x, y);
	update(1, w[x], w[y], val);
}

int n, m, p, c1, c2, k;
char str[5];

int main(){
	while(scanf("%d %d %d", &n, &m, &p) != EOF){
		for(int i=1;i<=n;i++) scanf("%d", &num[i]);
		int u, v;
		for(int i=1;i<=n;i++){
			edg[i].clear();
			fa[i] = -1;
		}
		for(int i=0;i<m;i++){
			scanf("%d %d", &u, &v);
			edg[u].push_back(v);
			edg[v].push_back(u);
		}
		tot = 0;
		fa[1] = 1;
		siz[0] = 0;
		dep[1] = 1;
		dfs1(1);
		dfs2(1, 1);
		build_tree(1, 1, n);
		while(p--){
			scanf("%s", str);
			if(str[0] == 'I'){
				scanf("%d %d %d", &c1, &c2, &k);
				add_val(c1, c2, k);
			}
			else if(str[0] == 'D'){
				scanf("%d %d %d", &c1, &c2, &k);
				add_val(c1, c2, -k);
			}
			else{
				scanf("%d", &c1);
				printf("%d\n", ask(1, w[c1]));
			}
		}
	}
	return 0;
}

I

树链剖分+线段树单点更新区间求最大值

#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#define maxn 100010

using namespace std;

struct Node{
	int l, r, val;
}tree[maxn * 4];

void build_tree(int id, int l, int r){
	tree[id].l = l;
	tree[id].r = r;
	tree[id].val = 0;
	if(l != r){
		int mid = (l + r) / 2;
		build_tree(id * 2, l, mid);
		build_tree(id * 2 + 1, mid + 1,  r);
	}
}

void updata(int pos, int val){
	int id = 1;
	while(tree[id].l != tree[id].r){
		int mid = (tree[id].l + tree[id].r) / 2;
		if(pos <= mid) id *= 2;
		else id = id * 2 + 1;
	}
	tree[id].val = val;
	while(id > 1){
		id /= 2;
		tree[id].val = max(tree[id * 2].val, tree[id * 2 + 1].val);
	}
}

int ask(int id, int ls, int rs){
	if(tree[id].l >= ls && tree[id].r <= rs) return tree[id].val;
	if(tree[id].l > rs || tree[id].r < ls) return 0;
	return max(ask(id * 2, ls, rs), ask(id * 2 + 1, ls, rs));
}


int link[maxn], ids;
int dep[maxn], fa[maxn], son[maxn], siz[maxn], top[maxn];
vector<int>edg[maxn];

void dfs1(int u){
	siz[u] = 1; son[u] = 0;
	for(int i=0;i<edg[u].size();i++) if(edg[u][i] != fa[u]){
		fa[edg[u][i]] = u;
		dep[edg[u][i]] = dep[u] + 1;
		dfs1(edg[u][i]);
		siz[u] += siz[edg[u][i]];
		if(siz[edg[u][i]] > siz[son[u]])
			son[u] = edg[u][i];
	}
}

void dfs2(int u, int tp){
	top[u] = tp;
	link[u] = ids++;
	if(son[u] == 0) return ;
	dfs2(son[u], tp);
	for(int i=0;i<edg[u].size();i++){
		if(edg[u][i] != son[u] && edg[u][i] != fa[u])
			dfs2(edg[u][i], edg[u][i]);
	}
}

int T, n, u[maxn], v[maxn], ws[maxn];
char str[10];

void ChangeVal(int id, int val){
	if(fa[u[id]] == v[id]) swap(u[id], v[id]);
	updata(link[v[id]], val);
}

int AskMax(int x, int y){
	int ans = 0;
	while(top[x] != top[y]){
		if(dep[top[x]] > dep[top[y]]) swap(x, y);
		ans = max(ans, ask(1, link[top[y]], link[y]));
		y = fa[top[y]];
	}
	if(x == y) return ans;
	if(dep[x] > dep[y]) swap(x, y);
	return max(ans, ask(1, link[son[x]], link[y]));
}

int main(){
	scanf("%d", &T);
	while(T--){
		scanf("%d", &n);
		for(int i=1;i<=n;i++) edg[i].clear();
		for(int i=1;i<n;i++){
			scanf("%d %d %d", &u[i], &v[i], &ws[i]);
			edg[u[i]].push_back(v[i]);
			edg[v[i]].push_back(u[i]);
			fa[i] = -1;
		}
		ids = 1; fa[n] = -1;
		siz[0] = 0; dep[1] = 1;
		dfs1(1);
		dfs2(1, 1);
		build_tree(1, 1, n);
		for(int i=1;i<n;i++) ChangeVal(i, ws[i]);
		int x, y;
		while(true){
			scanf("%s", str);
			if(str[0] == 'D') break;
			if(str[0] == 'C'){
				scanf("%d %d", &x, &y);
				ChangeVal(x, y);
			}
			else{
				scanf("%d %d", &x, &y);
				printf("%d\n", AskMax(x, y));
			}
		}
	}
	return 0;
}


你可能感兴趣的:(ACM)