树上操作 --- 树链剖分 + 线段树

传送门:洛谷2590


题目描述
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身


分析

裸的树链剖分,对于单点修改+区间求和+区间最值,直接用线段树维护就好了.
树状数组写挂了,尴尬


代码

#include <cstdio>
#include <cstdlib>
#include <cstring>

#define IL inline

using namespace std;

IL int read()
{
    char c = getchar();
    int sum = 0 ,k = 1;
    for(;'0' > c || c > '9'; c = getchar())
        if(c == '-') k = -1;
    for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
    return sum * k;
}

const int maxn = 3e4 + 5, inf = 0x3f3f3f3f;
int n;
int num[maxn];
int to[maxn << 1], nxt[maxn << 1];
int cnt;
int last[maxn];
IL void add(int u, int v)
{
    ++cnt; to[cnt] = v; nxt[cnt] = last[u]; last[u] = cnt;
    ++cnt; to[cnt] = u; nxt[cnt] = last[v]; last[v] = cnt;
}

int fa[maxn], dep[maxn], size[maxn], son[maxn];
int dfn, top[maxn], seg[maxn];

struct node
{
    node *lch, *rch;
    int sum, ma;
    IL node()
    {
        lch = rch = 0; sum = 0;
        ma = -inf;
    }
}* root;

IL int max_(int x, int y) { return x > y ? x : y; }
IL void swap_(int &x, int &y) { int tmp = x; x = y; y = tmp;}

IL void dfs1(int u)
{
    size[u] = 1;
    for(int i = last[u], v; v = to[i]; i = nxt[i])
    if(v != fa[u])
    {
        fa[v] = u;
        dep[v] = dep[u] + 1;
        dfs1(v);
        if(size[v] > size[son[u]]) son[u] = v;
        size[u] += size[v];
    }
}

IL void dfs2(int u, int topf)
{
    top[u] = topf;
    seg[u] = ++dfn;
    if(!son[u]) return ;
    dfs2(son[u], topf);
    for(int i = last[u], v; v = to[i]; i = nxt[i])
    if(v != fa[u] && v != son[u])
        dfs2(v, v);
}

IL void pushup(node *p)
{
    p->sum = p->lch->sum + p->rch->sum;
    p->ma = max_(p->lch->ma, p->rch->ma);
}

IL void build(node *p, int l, int r)
{
    if(l == r) { p->sum = p->ma = num[l];  return ;}
    int mid = (l + r) >> 1;
    p->lch = new node; build(p->lch, l, mid);
    p->rch = new node; build(p->rch, mid + 1, r);
    pushup(p);
}

IL void update(node *p, int l, int r, int k)
{
    if(l == r) { p->sum = p->ma = num[l];  return ;}
    int mid = (l + r) >> 1;
    if(k <= mid) update(p->lch, l, mid, k); else update(p->rch, mid + 1, r, k);
    pushup(p);
}

IL int querysum(node *p, int l, int r, int x, int y)
{
    if(l == x && r == y) return p->sum;
    int mid = (l + r) >> 1;
    if(y <= mid) return querysum(p->lch, l, mid, x, y);
    if(mid < x) return querysum(p->rch, mid + 1, r, x, y);
    return querysum(p->lch, l, mid, x, mid) + querysum(p->rch, mid + 1, r, mid + 1, y);
}

IL int querymax(node *p, int l, int r, int x, int y)
{
    if(l == x && r == y) return p->ma;
    int mid = (l + r) >> 1;
    if(y <= mid) return querymax(p->lch, l, mid, x, y);
    if(mid < x) return querymax(p->rch, mid + 1, r, x, y);
    return max_(querymax(p->lch, l, mid, x, mid), querymax(p->rch, mid + 1, r, mid + 1, y));
}

IL int solve(int x, int y, bool k)
{   
    int ans = k ? 0 : -inf;
    for(;top[x] != top[y];)
    {
        if(dep[top[x]] < dep[top[y]]) swap_(x, y);
        if(k) ans += querysum(root, 1, n, seg[top[x]], seg[x]); else ans = max_(ans, querymax(root, 1, n, seg[top[x]], seg[x]));
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap_(x, y);
    if(k) ans += querysum(root, 1, n, seg[x], seg[y]); else ans = max_(ans, querymax(root, 1, n, seg[x], seg[y]));
    return ans;
}


int main()
{
    n = read();
    for(int i = 1; i < n; ++i)
        add(read(), read());
    dfs1(1);
    dfs2(1, 1);
    for(int i = 1; i <= n; ++i) num[seg[i]] = read();
    root = new node;
    build(root, 1, n);
    char c[10];
    for(int m = read(), x, y; m; --m)
    {
        scanf(" %s", c); x = read(); y = read();
        if(c[0] == 'C')
        {
            num[seg[x]] = y;
            update(root, 1, n, seg[x]);
        }else
        if(c[0] == 'Q')
            printf("%d\n", solve(x, y, c[1] == 'S'));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/81291266
今日推荐