【树链剖分】[BZOJ1036][ZJOI2008]树的统计Count

题目描述

一棵树上有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本身

输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

样例输入

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

样例输出

4
1
2
2
10
6
5
6
5
16

题目分析

我们可以通过观察题目发现emoji难道这不是一个裸的树链剖分么。。。。。。每次操作复杂度 O(logN) 。。总复杂度 O(QlogN) 。。。这数据刚刚好。。写树链剖分吧,我记得树链剖分是可以用来求LCA的,就按照那个方法搞一搞就好了

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 30000;
const int MAXQ = 200000;
struct node{
    int v;
    node *next;
}Edges[MAXN*2+10], *ecnt=Edges, *adj[MAXN+10];
int Maxson[MAXN+10], sz[MAXN+10], id[MAXN+10], idcnt, top[MAXN+10], vals[MAXN+10], Dep[MAXN+10], Fa[MAXN+10], revid[MAXN+10];
void addedge(int u, int v){
    ++ecnt;
    ecnt->v = v;
    ecnt->next = adj[u];
    adj[u] = ecnt;
}
void dfs(int u, int fa){
    sz[u]=1;
    Fa[u] = fa;
    Dep[u]=Dep[fa]+1;
    for(node *p=adj[u];p;p=p->next){
        if(p->v == fa) continue;
        dfs(p->v, u);
        sz[u] += sz[p->v];
        if(sz[p->v] > sz[Maxson[u]])
            Maxson[u] = p->v;
    }
}
void dfs2(int u, int tp, int fa){
    top[u] = tp;
    revid[(id[u]=++idcnt)]=u;
    if(Maxson[u]) dfs2(Maxson[u], tp, u);
    for(node *p=adj[u];p;p=p->next){
        if(p->v==fa||p->v==Maxson[u]) continue;
        dfs2(p->v, p->v, u);
    }
}
struct Tree{
    int Max, Sum;
}tree[MAXN*4+10];
void push_up(int u){
    tree[u].Max = max(tree[u*2].Max, tree[u*2+1].Max);
    tree[u].Sum = tree[u*2].Sum + tree[u*2+1].Sum;
}
void Update(int u, int l, int r, int p, int v){
    if(l == r){
        tree[u].Max = tree[u].Sum = v;
        return ;
    }else{
        int mid = (l + r) >> 1;
        if(p<=mid)Update(u*2, l, mid, p, v);
        else Update(u*2+1, mid+1, r, p, v);
        push_up(u);
    }
}
int sumq(int u, int l, int r, int ql, int qr){
    if(ql <= l && r <= qr)
        return tree[u].Sum;
    else if(ql > r || qr < l)
        return 0;
    int mid = (l + r) >> 1;
    if(ql > mid) return sumq(u*2+1, mid+1, r, ql, qr);
    else if(qr <= mid) return sumq(u*2, l, mid, ql, qr);
    return sumq(u*2, l, mid, ql, qr) + sumq(u*2+1, mid+1, r, ql, qr);
}
int maxq(int u, int l, int r, int ql, int qr){
    if(ql <= l && r <= qr) return tree[u].Max;
    int mid = (l + r) >> 1;
    if(ql > mid) return maxq(u*2+1, mid+1, r, ql, qr);
    else if(qr <= mid) return maxq(u*2, l, mid, ql, qr);
    return max(maxq(u*2, l, mid, ql, qr), maxq(u*2+1, mid+1, r, ql, qr));
}
int Qsum(int l, int r){
    int f1 = top[l], f2 = top[r], ret = 0;
    while(f1 != f2){
        if(Dep[f1] < Dep[f2]){
            swap(f1, f2);
            swap(l, r);
        }
        ret += sumq(1, 1, idcnt, id[f1], id[l]);
        l = Fa[f1];
        f1 = top[l];
    }
    if(Dep[l] > Dep[r])
        swap(l, r);
    return ret + sumq(1, 1, idcnt, id[l], id[r]);
}
int Qmax(int l, int r){
    int f1 = top[l], f2 = top[r], ret = -1000000000;
    while(f1 != f2){
        if(Dep[f1] < Dep[f2]){
            swap(f1, f2);
            swap(l, r);
        }
        ret = max(ret, maxq(1, 1, idcnt, id[f1], id[l]));
        l = Fa[f1];
        f1 = top[l];
    }
    if(Dep[l] > Dep[r])
        swap(l, r);
    return max(ret, maxq(1, 1, idcnt, id[l], id[r]));
}
void dfs3(int u, int l, int r){
    if(l == r){
        tree[u].Max = tree[u].Sum = vals[revid[l]];
        return ;
    }
    int mid = (l + r) >> 1;
    dfs3(u*2, l, mid);
    dfs3(u*2+1, mid+1, r);
    push_up(u);
}
int main(){
    int n, u, v;
    scanf("%d", &n);
    for(int i=1;i<n;i++){
        scanf("%d%d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }
    dfs(1, 0);
    dfs2(1, 1, 0);
    for(int i=1;i<=n;i++)
        scanf("%d", &vals[i]);
    dfs3(1, 1, idcnt);
    int q, a, b;
    char ord[40];
    scanf("%d", &q);
    while(q--){
        scanf("%s%d%d", ord, &a, &b);
        if(ord[0] == 'C')
            Update(1, 1, idcnt, id[a], b);
        else{
            if(ord[1] == 'S')
                printf("%d\n", Qsum(a, b));
            else
                printf("%d\n", Qmax(a, b));
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值