1、题目大意:给你一棵树,有三种操作

1>qmax,询问u到v中间点权的最大值

2>qsum,询问u到v中间点权和

3>change,把u这个节点的权值改为v

2、分析:树链剖分的裸题,搞了一个礼拜。。。

需要维护的东西

1>height[x] x的深度

2>Top[x] x所在树链的最顶端

3>num[x] x在线段树的标号

4>father[x] x的父亲

5>size[x] 以x为根的字数的节点数

6>value[x] x的权值

7>segment_tree

哪个儿子的size最大,那么连着这个儿子的边就是重边

然后比如求点权最大值,然后就让Top值最大的那个点往上跳到father[Top[这个点]],更新ret,直到u和v是同一个链上的

线段树就搞一搞,求和也是类似的,修改就是线段树单点的修改

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
struct segment_tree{
    int q[1001000];
    int sum[1001000];
    int x, y;
    void init(){
        for(int i = 1; i <= 1000000; i ++) q[i] = -2147483647;
        return;
    }
    void add(int l, int r, int o){
        if(l == r && x == l){
            sum[o] = q[o] = y;
            return;
        }
        int mid = (l + r) / 2;
        if(x <= mid) add(l, mid, 2 * o);
        if(x > mid) add(mid + 1, r, 2 * o + 1);
        q[o] = max(q[2 * o], q[2 * o + 1]);
        sum[o] = sum[2 * o] + sum[2 * o + 1];
        return;
    }
    int query_max(int l, int r, int o){
        if(x <= l && r <= y){
            return q[o];
        }
        int mid = (l + r) / 2;
        int ret = -2147483647;
        if(x <= mid) ret = max(ret, query_max(l, mid, 2 * o));
        if(y > mid) ret = max(ret, query_max(mid + 1, r, 2 * o + 1));
        return ret;
    }
    int query_sum(int l, int r, int o){
        if(x <= l && r <= y){
            return sum[o];
        }
        int mid = (l + r) / 2;
        int ret = 0;
        if(x <= mid) ret += query_sum(l, mid, 2 * o);
        if(y > mid) ret += query_sum(mid + 1, r, 2 * o + 1);
        return ret;
    }
} qzh;
struct node{
    int from, to, next;
};
struct tree_chain_partition{
    int Top[1000100];
    int Size[1000100];
    int height[1000100];
    int father[1000100];
    int num[1000100];
    int value[1000100];
    node G[1000100];
    int head[1000100];
    int ff;
    int de;
    int n;
    void init(){
        memset(head, -1, sizeof(head));
        ff = -1;
        return;
    }
    void insert(int u, int v){
        ff ++;
        G[ff] = (node){u, v, head[u]};
        head[u] = ff;
        return;
    }
    void dfs1(int x, int fa, int k){
        father[x] = fa;
        height[x] = k;
        Size[x] = 1;
        for(int i = head[x]; i != -1; i = G[i].next){
            node e = G[i];
            if(e.to != fa){
                dfs1(e.to, x, k + 1);
                Size[x] += Size[e.to];
            }
        }
        return;
    }
    void dfs2(int x, int fa){
        int o = 0, pos;
        for(int i = head[x]; i != -1; i = G[i].next){
            node e = G[i];
            if(Size[e.to] > o && e.to != fa){
                pos = i;
                o = Size[e.to];
            }
        }
        if(o != 0){
            qzh.x = ++ de;
            qzh.y = value[G[pos].to];
            qzh.add(1, n, 1);
            num[G[pos].to] = de;
            Top[G[pos].to] = Top[x];
            dfs2(G[pos].to, x);
        }
        for(int i = head[x]; i != -1; i = G[i].next){
            node e = G[i];
            if(e.to != fa && i != pos){
                qzh.x = ++ de;
                qzh.y = value[e.to];
                qzh.add(1, n, 1);
                num[e.to] = de;
                Top[e.to] = e.to;
                dfs2(e.to, x);
            }
        }
        return;
    }
    void solve(){
        qzh.init();
        dfs1(1, 0, 1);
        qzh.x = ++ de;
        qzh.y = value[1];
        qzh.add(1, n, 1);
        num[1] = de;
        Top[1] = 1;
        dfs2(1, 0);
        return;
    }
    void change(int s, int t){
        qzh.x = num[s];
        qzh.y = t;
        qzh.add(1, n, 1);
        return;
    }
    int qmax(int s, int t){
        int ret = -2147483647;
        while(Top[s] != Top[t]){
            if(height[Top[s]] > height[Top[t]]) swap(s, t);
            qzh.x = num[Top[t]];
            qzh.y = num[t];
            ret = max(ret, qzh.query_max(1, n, 1));
            t = father[Top[t]];
        }
        if(height[s] > height[t]) swap(s, t);
        qzh.x = num[s];
        qzh.y = num[t];
        ret = max(ret, qzh.query_max(1, n, 1));
        return ret;
    }
    int qsum(int s, int t){
        int ret = 0;
        while(Top[s] != Top[t]){
            if(height[Top[s]] > height[Top[t]]) swap(s, t);
            qzh.x = num[Top[t]];
            qzh.y = num[t];
            ret += qzh.query_sum(1, n, 1);
            t = father[Top[t]];
        }
        if(height[s] > height[t]) swap(s, t);
        qzh.x = num[s];
        qzh.y = num[t];
        ret += qzh.query_sum(1, n, 1);
        return ret;
    }
} wt;
int main(){
    wt.init();
    scanf("%d", &wt.n);
    for(int i = 1; i < wt.n; i ++){
        int u, v;
        scanf("%d%d", &u, &v);
        wt.insert(u, v);
        wt.insert(v, u);
    }
    for(int i = 1; i <= wt.n; i ++) scanf("%d", &wt.value[i]);
    int q;
    scanf("%d", &q);
    wt.solve();
    while(q --){
        char str[10];
        int u, v;
        scanf("%s%d%d", str, &u, &v);
        if(str[1] == 'H') wt.change(u, v);
        else if(str[1] == 'M') printf("%d\n", wt.qmax(u, v));
        else printf("%d\n", wt.qsum(u, v));
    }
    return 0;
} 

BZOJ1036——树的统计count的更多相关文章

  1. BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)

    潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...

  2. bzoj1036 树的统计Count

    第一次写链剖,于是挑了个简单的裸题写. 以下几点要注意: 1.链剖中的height是从根到该店经过的轻边个数 2.分清num与sum..... #include<cstdio> #incl ...

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

    [BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...

  4. [BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分

    树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设( ...

  5. bzoj1036 [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 12646  Solved: 5085 [Subm ...

  6. bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

    [ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...

  7. bzoj千题计划124:bzoj1036: [ZJOI2008]树的统计Count

    http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分板子题 #include<cstdio> #include<iost ...

  8. BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14302  Solved: 5779[Submit ...

  9. BZOJ 1036: [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 14354  Solved: 5802 [Subm ...

随机推荐

  1. JavaWeb---总结(十七)JSP中的九个内置对象

    一.JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet ...

  2. SSL/TLS协议工作流程

    我看了CloudFlare的说明(这里和这里),突然意识到这是绝好的例子,可以用来说明SSL/TLS协议的运行机制.它配有插图,很容易看懂. 下面,我就用这些图片作为例子,配合我半年前写的<SS ...

  3. CentOS7搭建hadoop2.6.4双节点集群

    环境: CentOS7+SunJDK1.8@VMware12. NameNode虚拟机节点主机名:master,IP规划:192.168.23.101,职责:Name node,Secondary n ...

  4. Runner站立会议07

    开会时间:21.10~21.30 地点:基教负一 今天做了什么:看网上下载的日历代码 明天准备做什么:继续看代码 遇到的困难:下载的代码有很多看不懂的地方,很多包.函数等都不知道 会议图: 燃尽图:

  5. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现——Post(新 ...

  6. Python 调用 user32.dll

    import ctypes h = ctypes.windll.LoadLibrary("C:\\Windows\\System32\\user32.dll") h.Message ...

  7. Only one statement is allowed per batch. A batch separator, such as 'GO', might be required between statements.

    When I added the file in VS I forgot to set Build Action = None from the file properties.

  8. Using Friendly URLs in ASP.NET Web Forms

    Introduction Websites often need to generate SEO friendly URLs. In ASP.NET Web Forms applications, a ...

  9. 对Java Serializable(序列化)的理解和总结

    我对Java Serializable(序列化)的理解和总结 博客分类: Java技术 JavaOSSocketCC++  1.序列化是干什么的?       简单说就是为了保存在内存中的各种对象的状 ...

  10. thinkphp 3.2 视图模型 实例 视图查询结果 二维数组 合并

    使用视图模型查询的时候 结果是这样的 array(6) { [0] => array(5) { ["picTitle"] => string(7) "标题2& ...