bzoj 1036 ZJOI2008 树的统计count (树链剖分

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 3401   Solved: 1418
[ Submit][ Status]

Description

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

Input

输入的第一行为一个整数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之间。

Output

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

Sample Input

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

Sample Output

4
1
2
2
10
6
5
6
5
16

 一个树链剖分的入门题。 具体的树链剖分的 讲解推荐

http://www.cnblogs.com/937337156Zhang/p/6047165.html

http://www.cnblogs.com/sagitta/p/5660749.html

这俩配合使用。。。

然后我的代码是改的kuangbin的模板。。

//
//  ZJOI树的统计count(树链剖分.cpp
//  HDOJ
//
//  Created by 张智超 on 01/10/2017.
//  Copyright © 2017 张智超. All rights reserved.
//
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <utility>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 30010;
struct Edge {
    int v, next;
}edge[maxn << 1];
int head[maxn], total;//邻接表
int top[maxn]; //top[v] 表示v所在的重链的顶端节点
int fa[maxn]; //父亲节点
int deep[maxn];//深度
int son_num[maxn];//son_num[v]表示v为根的子树的节点数
int pos[maxn];//pos[v] v在线段树中的位置
int fpos[maxn];//和pos数组相反,由位置记录点
int son[maxn];//重儿子
int cur_pos;
inline void init() {
    total = 0;
    memset(head, -1, sizeof(head));
    cur_pos = 0;
    memset(son, -1, sizeof(son));
}

inline void add(int u, int v) {
    edge[total] = {v, head[u]};
    head[u] = total++;
}

//第一遍dfs求fa deep son_num son
void dfs1(int u, int pre, int de) {
    deep[u] = de;
    fa[u] = pre;
    son_num[u] = 1;
    
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].v;
        if (v != pre) {
            dfs1(v, u, de + 1);
            son_num[u] += son_num[v];
            if (son[u] == -1 || son_num[v] > son_num[son[u]])
                son[u] = v;
        }
    }
}

void get_pos(int u, int sp) {
    top[u] = sp;
    pos[u] = ++cur_pos;
    ::fpos[pos[u]] = u;
    if (son[u] == -1)
        return;
    get_pos(son[u], sp);
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].v;
        if (v != son[u] && v != fa[u]) {
            get_pos(v, v);
        }
    }
}


struct Node {
    int left, right;
    int sum;
    int max;
}seg_tree[maxn << 2];

inline void push_up(int i) {
    seg_tree[i].sum = seg_tree[i << 1].sum + seg_tree[i << 1 | 1].sum;
    seg_tree[i].max = max(seg_tree[i << 1].max, seg_tree[i << 1 | 1].max);
}

int arr[maxn];

void build(int i, int left, int right) {
    seg_tree[i].left = left;
    seg_tree[i].right = right;
    if (left == right) {
        seg_tree[i].sum = seg_tree[i].max = arr[::fpos[left]];
        return;
    }
    int mid = (left + right) >> 1;
    build(i << 1, left, mid);
    build(i << 1 | 1, mid + 1, right);
    push_up(i);
}
//更新线段树第k个值为val
void update(int i, int k, int val) {
    if (seg_tree[i].left == k && seg_tree[i].right == k) {
        seg_tree[i].sum = seg_tree[i].max = val;
        return;
    }
    int mid = (seg_tree[i].left + seg_tree[i].right) >> 1;
    if (k <= mid)
        update(i << 1, k, val);
    else
        update(i << 1 | 1, k, val);
    push_up(i);
}
//查询线段树[left, right]区间最大值

int query_max(int i, int left, int right) {
    if (seg_tree[i].left >= left && right >= seg_tree[i].right)
        return seg_tree[i].max;
    int mid = (seg_tree[i].left + seg_tree[i].right) >> 1;
    int ans = -INF;
    if (mid >= left)
        ans = max(ans, query_max(i << 1, left, mid));
    if (mid < right)
        ans = max(ans, query_max(i << 1 | 1, left, right));
    return ans;
}

int query_sum(int i, int left, int right) {
    if (seg_tree[i].left >= left && right >= seg_tree[i].right) {
            //cout <<"  l  " <<seg_tree[i].left  << " begin " << left << "  r "  << seg_tree[i].right  << " end" << right<< endl;
        return seg_tree[i].sum;
    }
    int ans = 0;
    int mid = (seg_tree[i].left + seg_tree[i].right) >> 1;
    if (mid >= left)
        ans += query_sum(i << 1, left, mid);
    if (mid < right)
        ans += query_sum(i << 1 | 1, left, right);
    return ans;
}
//查询u->v路径上节点权值的和
int find_max(int u, int v) {
    int f1 = top[u], f2 = top[v];
    int tmp = -INF;
    while (f1 != f2) {
        if (deep[f1] < deep[f2]) {
            swap(f1, f2);
            swap(u, v);
        }
        tmp = max(tmp, query_max(1, pos[f1], pos[u]));
        u = fa[f1];
        f1 = top[u];
    }
    if (deep[u] > deep[v])
        swap(u, v);
    return max(tmp, query_max(1, pos[u], pos[v]));
}
//查询u->v路径上的节点的权值的和
int find_sum(int u, int v) {
    int f1 = top[u], f2 = top[v];
    int ans = 0;
    while (f1 != f2) {
        if (deep[f1] < deep[f2]) {
            swap(u, v);
            swap(f1, f2);
        }
        ans += query_sum(1, pos[f1], pos[u]);
            //cout << "f1:"<<f1 << " u:" << u << " " << ans << endl;

        u = fa[f1];
        f1 = top[u];
    }
    if (deep[u] > deep[v])
        swap(u, v);
    return ans + query_sum(1, pos[u], pos[v]);
}

void print(int i, int l, int r) {
    if (l == r) {
        cout << seg_tree[i].sum << " ";
        return;
    }
    int mid = (l + r) >> 1;
    print(i << 1, l, mid);
    print(i << 1 | 1, mid + 1, r);
}
int main() {
    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n, q, u, v;
    char op[20];
    while (cin >> n) {
        init();
        for (int i = 1; i < n; ++i) {
            cin >> u >> v;
            add(u, v);
            add(v, u);
        }
        for (int i = 1; i <= n; ++i) {
            cin >> arr[i];
        }
        dfs1(1, 0, 1);
        get_pos(1, 1);
        build(1, 1, cur_pos);
        cin >> q;
        while (q--) {
            cin >> op >> u >> v;
                //print(1, 1, cur_pos);
                //cout << endl;
                //cout << u << " " << v << endl;
            if (op[0] == 'C') {
                update(1, pos[u], v);
            } else if (strcmp(op, "QMAX") == 0){
                cout << find_max(u, v) << endl;
            } else {
                cout << find_sum(u, v) << endl;
            }
        }
    }
}


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值