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\n", qans); }
}
}
return 0;
}