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;
}

你可能感兴趣的:(POJ 3237 Tree 树链剖分)