Query on a tree SPOJ - QTREE 树链剖分 模板

题目链接:Query on a tree

题目大意

一棵树,有n个节点n<=1e4, 有两种操作:1.求节点a和b之间路径的最大权值的边;2. 将边i的权值改为ti

思路

树链剖分,边的权值存在儿子节点上,线段树求区间值和修改

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e4 + 10, inf = 0x3f3f3f3f;

int n, mx[maxn << 2];
int cost[maxn];
struct edge
{
    int to, cost, nxt;
    edge(int to = 0, int cost = 0, int nxt = 0)
    {
        this->to = to;
        this->cost = cost;
        this->nxt = nxt;
    }
};
edge es[maxn * 2];
int head[maxn];
inline void addedge(int id, int u, int v, int cost)
{
    es[id * 2] = edge(v, cost, head[u]);
    head[u] = id * 2;
    es[id * 2 + 1] = edge(u, cost, head[v]);
    head[v] = id * 2 + 1;
}

#define ls l, m, rt<<1
#define rs m+1, r, rt<<1|1
inline void pushUp(int rt)
{
    mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
}
void build(int l, int r, int rt)
{
    if (l == r)
    {
        mx[rt] = cost[l];
        return;
    }
    int m = (l + r) >> 1;
    build(ls);
    build(rs);
    pushUp(rt);
}
void update(int p, int v, int l, int r, int rt)
{
    if (l == r)
    {
        mx[rt] = v;
        return;
    }
    int m = (l + r) >> 1;
    if (p <= m) update(p, v, ls);
    else update(p, v, rs);
    pushUp(rt);
}
int query(int L, int R, int l, int r, int rt)
{
    if (L <= l && r <= R) return mx[rt];
    if (l > R || r < L) return -inf;
    int m = (l + r) >> 1;
    return max(query(L, R, ls), query(L, R, rs));
}

int siz[maxn];
int top[maxn];
int son[maxn];
int dep[maxn];
int faz[maxn];
int id[maxn];
int rid[maxn];
int dfs_clocks;
void init(int n)
{
    memset(head, 0, sizeof(int) * (n + 1));
    memset(son , -1, sizeof(int) * (n + 1));
    dfs_clocks = 1;
}
void dfs1(int u, int fa, int depth)
{
    dep[u] = depth;
    faz[u] = fa;
    siz[u] = 1;

    for (int i = head[u]; i; i = es[i].nxt)
    {
        int v = es[i].to;
        if (v == fa) continue;
        dfs1(v, u, depth + 1);
        siz[u] += siz[v];
        if (son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;
    }
}
void dfs2(int u, int tp)
{
    top[u] = tp;
    id[u] = dfs_clocks;
    rid[dfs_clocks++] = u;

    if (son[u] == -1) return;

    dfs2(son[u], tp);

    for (int i = head[u]; i; i = es[i].nxt)
    {
        int v = es[i].to;
        if (v != son[u] && v != faz[u]) dfs2(v, v);
    }
}

int query_path(int x, int y)
{
    int ret = -inf;
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        ret = max(ret, query(id[top[x]], id[x], 1, n, 1));
        x = faz[top[x]];//error: x = faz[x];
    }

    if (x != y)
    {
        if (id[x] > id[y]) swap(x, y);
        ret = max(ret, query(id[son[x]], id[y], 1, n, 1));
    }
    return ret;
}
void update_path(int eid, int v)
{
    int x = dep[es[eid * 2].to] > dep[es[eid * 2 + 1].to] ?
            es[eid * 2].to : es[eid * 2 + 1].to;
    update(id[x], v, 1, n, 1);//error: update(x, v, 1, n, 1);
}

int main()
{
    int T;
    for (scanf("%d", &T); T; --T)
    {
        scanf("%d", &n);
        init(n);
        int a, b, c;
        for (int i = 1; i < n; ++i)
        {
            scanf("%d%d%d", &a, &b, &c);
            addedge(i, a, b, c);
        }
        dfs1(1, 1, 1);
        dfs2(1, 1);
        for (int i = 1; i <= n - 1; ++i)
        {
            int x = dep[es[i * 2].to] > dep[es[i * 2 + 1].to] ?
                    es[i * 2].to : es[i * 2 + 1].to;
            cost[id[x]] = es[i * 2].cost;
        }
        build(1, n, 1);
        char q[20];
        while (scanf("%s", q))
        {
            if (q[0] == 'Q')
            {
                scanf("%d%d", &a, &b);
                printf("%d\n", query_path(a, b));
            }
            else if (q[0] == 'C')
            {
                scanf("%d%d", &a, &b);
                update_path(a, b);
            }
            else break;
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/litmxs/article/details/81083945