POJ 3237 Tree 树链剖分

题意:

给出一棵树,每条边有一个权值。下面有3种操作:

  • 改变某条边的权值
  • 将一条路径上的所有边的权值取反
  • 查询一条路径上的最大权值

分析:

因为是线段树成段取反操作,可以先打个neg标记,表示这段区间的数是否取反。
再维护区间最大值和最小值,取反之后,新区间的最大值是原来最小值的相反数,新区间最小值是原来最大值的相反数。

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

const int maxn = 10000 + 10;
const int maxnode = maxn * 4;

struct Edge
{
	int v, nxt;
	Edge() {}
	Edge(int v, int nxt): v(v), nxt(nxt) {}
};

int n, u[maxn], v[maxn], w[maxn];
int ecnt, head[maxn];
Edge edges[maxn * 2];

void AddEdge(int u, int v) {
	edges[++ecnt] = Edge(v, head[u]);
	head[u] = ecnt;
	edges[++ecnt] = Edge(u, head[v]);
	head[v] = ecnt;
}

int tot;
int sz[maxn], fa[maxn], dep[maxn], son[maxn], up[maxn];
int id[maxn], pos[maxn], top[maxn];

void dfs(int u) {
	sz[u] = 1; son[u] = 0;
	for(int i = head[u]; i; i = edges[i].nxt) {
		int v = edges[i].v;
		if(v == fa[u]) continue;
		fa[v] = u;
		dep[v] = dep[u] + 1;
		up[v] = (i + 1) / 2;
		dfs(v);
		sz[u] += sz[v];
		if(sz[v] > sz[son[u]]) son[u] = v;
	}
}

void dfs2(int u, int tp) {
	top[u] = tp;
	id[u] = tot;
	pos[tot++] = up[u];
	if(son[u]) dfs2(son[u], tp);
	for(int i = head[u]; i; i = edges[i].nxt) {
		int v = edges[i].v;
		if(v == fa[u] || v == son[u]) continue;
		dfs2(v, v);
	}
}

int maxv[maxnode], minv[maxnode], neg[maxnode];

void pushup(int o) {
	maxv[o] = max(maxv[o<<1], maxv[o<<1|1]);
	minv[o] = min(minv[o<<1], minv[o<<1|1]);
}

void build(int o, int L, int R) {
	if(L == R) {
		maxv[o] = minv[o] = w[pos[L]];
		neg[o] = 0;
		return;
	}
	int M = (L + R) / 2;
	build(o<<1, L, M);
	build(o<<1|1, M+1, R);
	pushup(o);
}

void Inverse(int& a, int &b) {
	swap(a, b); a = -a; b = -b;
}

void pushdown(int o) {
	if(neg[o]) {
		neg[o<<1] ^= 1;
		neg[o<<1|1] ^= 1;
		Inverse(maxv[o<<1], minv[o<<1]);
		Inverse(maxv[o<<1|1], minv[o<<1|1]);
		neg[o] = 0;
	}
}

void change(int o, int L, int R, int p, int v) {
	if(L == R) {
		maxv[o] = minv[o] = v;
		neg[o] = 0;
		return;
	}
	int M = (L + R) / 2;
	pushdown(o);
	if(p <= M) change(o<<1, L, M, p, v);
	else change(o<<1|1, M+1, R, p, v);
	pushup(o);
}

void update(int o, int L, int R, int qL, int qR) {
	if(qL <= L && R <= qR) {
		Inverse(minv[o], maxv[o]);
		neg[o] ^= 1;
		return;
	}
	int M = (L + R) / 2;
	pushdown(o);
	if(qL <= M) update(o<<1, L, M, qL, qR);
	if(qR > M) update(o<<1|1, M+1, R, qL, qR);
	pushup(o);
}

void UPDATE(int u, int v) {
	int t1 = top[u], t2 = top[v];
	while(t1 != t2) {
		if(dep[t1] < dep[t2]) { swap(u, v); swap(t1, t2); }
		update(1, 1, n, id[t1], id[u]);
		u = fa[t1]; t1 = top[u];
	}
	if(u == v) return;
	if(dep[u] > dep[v]) swap(u, v);
	update(1, 1, n, id[son[u]], id[v]);
}

int qans;

void query(int o, int L, int R, int qL, int qR) {
	if(qL <= L && R <= qR) { qans = max(qans, maxv[o]); return; }
	int M = (L + R) / 2;
	pushdown(o);
	if(qL <= M) query(o<<1, L, M, qL, qR);
	if(qR > M) query(o<<1|1, M+1, R, qL, qR);
}

void QUERY(int u, int v) {
	int t1 = top[u], t2 = top[v];
	qans = -1000000000;
	while(t1 != t2) {
		if(dep[t1] < dep[t2]) { swap(u, v); swap(t1, t2); }
		query(1, 1, n, id[t1], id[u]);
		u = fa[t1]; t1 = top[u];
	}
	if(u == v) return;
	if(dep[u] > dep[v]) swap(u, v);
	query(1, 1, n, id[son[u]], id[v]);
}

int main()
{
	freopen("in.txt", "r", stdin);

	int _; scanf("%d", &_);
	while(_--) {
		scanf("%d", &n);

		ecnt = 0;
		memset(head, 0, sizeof(head));
		for(int i = 1; i < n; i++) {
			scanf("%d%d%d", u + i, v + i, w + i);
			AddEdge(u[i], v[i]);
		}
	
		dfs(1);
		tot = 0;
		dfs2(1, 1);
		n--;
		memset(maxv, 0, sizeof(maxv));
		memset(minv, 0, sizeof(minv));
		memset(neg, 0, sizeof(neg));
		for(int i = 1; i <= n; i++)
			if(dep[u[i]] < dep[v[i]])
				swap(u[i], v[i]);
		build(1, 1, n);

		char cmd[10];
		int a, b;
		while(scanf("%s", cmd) == 1) {
			if(cmd[0] == 'D') break;
			scanf("%d%d", &a, &b);
			if(cmd[0] == 'C') change(1, 1, n, id[u[a]], b);
			else if(cmd[0] == 'N') UPDATE(a, b);
			else { QUERY(a, b); printf("%d
", qans); }
		}
	}

	return 0;
}
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/5186735.html