在大神的网站进不去的时候可以过来看看,另外道客巴巴有个排版比较好的文档,外观派可以去看看http://www.doc88.com/p-2728103209174.html

很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章了,觉得当时的代码风格实在是太丑了,很多线段树的初学者可能就是看着这篇文章来练习的,如果不小心被我培养出了这么糟糕的风格,实在是过意不去,正好过几天又要给集训队讲解线段树,所以决定把这些题目重新写一遍,顺便把近年我接触到的一些新题更新上去~;并且学习了splay等更高级的数据结构后对线段树的体会有更深了一层,线段树的写法也就比以前飘逸,简洁且方便多了.

在代码前先介绍一些我的线段树风格:




maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍


lson和rson分辨表示结点的左儿子和右儿子,由于每次传参数的时候都固定是这几个变量,所以可以用预定于比较方便的表示


以前的写法是另外开两个个数组记录每个结点所表示的区间,其实这个区间不必保存,一边算一边传下去就行,只需要写函数的时候多两个参数,结合lson和rson的预定义可以很方便


PushUP(int rt)是把当前结点的信息更新到父结点


PushDown(int rt)是把当前结点的信息更新给儿子结点


rt表示当前子树的根(root),也就是当前所在的结点


整理这些题目后我觉得线段树的题目整体上可以分成以下四个部分:




单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来


hdu1166 敌兵布阵
http://acm.hdu.edu.cn/showproblem.php?pid=1166


题意:O(-1)


思路:O(-1)


线段树功能:update:单点增减 query:区间求和


#include <cstdio>


 


#define lson l , m , rt << 1


#define rson m + 1 , r , rt << 1 | 1


const int maxn = 55555;


int sum[maxn<<2];


void PushUP(int rt) {


        sum[rt] = sum[rt<<1] + sum[rt<<1|1];


}


void build(int l,int r,int rt) {


        if (l == r) {


                scanf("%d",&sum[rt]);


                return ;


        }


        int m = (l + r) >> 1;


        build(lson);


        build(rson);


        PushUP(rt);


}


void update(int p,int add,int l,int r,int rt) {


        if (l == r) {


                sum[rt] += add;


                return ;


        }


        int m = (l + r) >> 1;


        if (p <= m) update(p , add , lson);


        else update(p , add , rson);


        PushUP(rt);


}


int query(int L,int R,int l,int r,int rt) {


        if (L <= l && r <= R) {


                return sum[rt];


        }


        int m = (l + r) >> 1;


        int ret = 0;


        if (L <= m) ret += query(L , R , lson);


        if (R > m) ret += query(L , R , rson);


        return ret;


}


int main() {


        int T , n;


        scanf("%d",&T);


        for (int cas = 1 ; cas <= T ; cas ++) {


                printf("Case %d:\n",cas);


                scanf("%d",&n);


                build(1 , n , 1);


                char op[10];


                while (scanf("%s",op)) {


                        if (op[0] == 'E') break;


                        int a , b;


                        scanf("%d%d",&a,&b);


                        if (op[0] == 'Q') printf("%d\n",query(a , b , 1 , n , 1));


                        else if (op[0] == 'S') update(a , -b , 1 , n , 1);


                        else update(a , b , 1 , n , 1);


                }


        }


        return 0;


}






hdu1754 I Hate It


http://acm.hdu.edu.cn/showproblem.php?pid=1754


题意:O(-1)


思路:O(-1)


线段树功能:update:单点替换 query:区间最值


#include <cstdio>


#include <algorithm>


using namespace std;


 


#define lson l , m , rt << 1


#define rson m + 1 , r , rt << 1 | 1


const int maxn = 222222;


int MAX[maxn<<2];


void PushUP(int rt) {


        MAX[rt] = max(MAX[rt<<1] , MAX[rt<<1|1]);


}


void build(int l,int r,int rt) {


        if (l == r) {


                scanf("%d",&MAX[rt]);


                return ;


        }


        int m = (l + r) >> 1;


        build(lson);


        build(rson);


        PushUP(rt);


}


void update(int p,int sc,int l,int r,int rt) {


        if (l == r) {


                MAX[rt] = sc;


                return ;


        }


        int m = (l + r) >> 1;


        if (p <= m) update(p , sc , lson);


        else update(p , sc , rson);


        PushUP(rt);


}


int query(int L,int R,int l,int r,int rt) {


        if (L <= l && r <= R) {


                return MAX[rt];


        }


        int m = (l + r) >> 1;


        int ret = 0;


        if (L <= m) ret = max(ret , query(L , R , lson));


        if (R > m) ret = max(ret , query(L , R , rson));


        return ret;


}


int main() {


        int n , m;


        while (~scanf("%d%d",&n,&m)) {


                build(1 , n , 1);


                while (m --) {


                        char op[2];


                        int a , b;


                        scanf("%s%d%d",op,&a,&b);


                        if (op[0] == 'Q') printf("%d\n",query(a , b , 1 , n , 1));


                        else update(a , b , 1 , n , 1);


                }


        }


        return 0;


}


hdu1394 Minimum Inversion Number


http://acm.hdu.edu.cn/showproblem.php?pid=1394


题意:求Inversion后的最小逆序数


思路:用O(nlogn)复杂度求出最初逆序数后,就可以用O(1)的复杂度分别递推出其他解


线段树功能:update:单点增减 query:区间求和


#include <cstdio>


#include <algorithm>


using namespace std;


 


#define lson l , m , rt << 1


#define rson m + 1 , r , rt << 1 | 1


const int maxn = 5555;


int sum[maxn<<2];


void PushUP(int rt) {


        sum[rt] = sum[rt<<1] + sum[rt<<1|1];


}


void build(int l,int r,int rt) {


        sum[rt] = 0;


        if (l == r) return ;


        int m = (l + r) >> 1;


        build(lson);


        build(rson);


}


void update(int p,int l,int r,int rt) {


        if (l == r) {


                sum[rt] ++;


                return ;


        }


        int m = (l + r) >> 1;


        if (p <= m) update(p , lson);


        else update(p , rson);


        PushUP(rt);


}


int query(int L,int R,int l,int r,int rt) {


        if (L <= l && r <= R) {


                return sum[rt];


        }


        int m = (l + r) >> 1;


        int ret = 0;


        if (L <= m) ret += query(L , R , lson);


        if (R > m) ret += query(L , R , rson);


        return ret;


}


int x[maxn];


int main() {


        int n;


        while (~scanf("%d",&n)) {


                build(0 , n - 1 , 1);


                int sum = 0;


                for (int i = 0 ; i < n ; i ++) {


                        scanf("%d",&x[i]);


                        sum += query(x[i] , n - 1 , 0 , n - 1 , 1);


                        update(x[i] , 0 , n - 1 , 1);


                }


                int ret = sum;


                for (int i = 0 ; i < n ; i ++) {


                        sum += n - x[i] - x[i] - 1;


                        ret = min(ret , sum);


                }


                printf("%d\n",ret);


        }


        return 0;


}


      成段更新


(通常这对初学者来说是一道坎),需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候


hdu1698 Just a Hook


http://acm.hdu.edu.cn/showproblem.php?pid=1698


题意:O(-1)


思路:O(-1)


线段树功能:update:成段替换 (由于只query一次总区间,所以可以直接输出1结点的信息


#include <cstdio>


#include <algorithm>


using namespace std;


 


#define lson l , m , rt << 1


#define rson m + 1 , r , rt << 1 | 1


const int maxn = 111111;


int h , w , n;


int col[maxn<<2];


int sum[maxn<<2];


void PushUp(int rt) {


        sum[rt] = sum[rt<<1] + sum[rt<<1|1];


}


void PushDown(int rt,int m) {


        if (col[rt]) {


                col[rt<<1] = col[rt<<1|1] = col[rt];


                sum[rt<<1] = (m - (m >> 1)) * col[rt];


                sum[rt<<1|1] = (m >> 1) * col[rt];


                col[rt] = 0;


        }


}


void build(int l,int r,int rt) {


        col[rt] = 0;


        sum[rt] = 1;


        if (l == r) return ;


        int m = (l + r) >> 1;


        build(lson);


        build(rson);


        PushUp(rt);


}


void update(int L,int R,int c,int l,int r,int rt) {


        if (L <= l && r <= R) {


                col[rt] = c;


                sum[rt] = c * (r - l + 1);


                return ;


        }


        PushDown(rt , r - l + 1);


        int m = (l + r) >> 1;


        if (L <= m) update(L , R , c , lson);


        if (R > m) update(L , R , c , rson);


        PushUp(rt);


}


int main() {


        int T , n , m;


        scanf("%d",&T);


        for (int cas = 1 ; cas <= T ; cas ++) {


                scanf("%d%d",&n,&m);


                build(1 , n , 1);


                while (m --) {


                        int a , b , c;


                        scanf("%d%d%d",&a,&b,&c);


                        update(a , b , c , 1 , n , 1);


                }


                printf("Case %d: The total value of the hook is %d.\n",cas , sum[1]);


        }


        return 0;


}

notonlysuccess大神的线段树完全版的更多相关文章

  1. 【转】线段树完全版~by NotOnlySuccess

    线段树完全版  ~by NotOnlySuccess 很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章了,觉 ...

  2. 【转】 线段树完全版 ~by NotOnlySuccess

    载自:NotOnlySuccess的博客 [完全版]线段树 很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章 ...

  3. LOJ2980 THUSC2017大魔法师(线段树+矩阵乘法)

    线段树每个节点维护(A,B,C,len)向量,操作即是将其乘上一个矩阵. #include<iostream> #include<cstdio> #include<cma ...

  4. BZOJ4530 BJOI2014大融合(线段树合并+并查集+dfs序)

    易知所求的是两棵子树大小的乘积.先建出最后所得到的树,求出dfs序和子树大小.之后考虑如何在动态加边过程中维护子树大小.这个可以用树剖比较简单的实现,但还有一种更快更优美的做法就是线段树合并.对每个点 ...

  5. 2019.01.14 bzoj4530: [Bjoi2014]大融合(线段树合并)

    传送门 线段树合并菜题. 题意简述:nnn个点,支持连边以及查询一个点所在连通块中经过这个点的路径条数,保证这张图时刻为森林. 思路: 先建出所有操作完之后的树统计出dfsdfsdfs序 注意有可能是 ...

  6. 【洛谷4219】[BJOI2014]大融合(线段树分治)

    题目: 洛谷4219 分析: 很明显,查询的是删掉某条边后两端点所在连通块大小的乘积. 有加边和删边,想到LCT.但是我不会用LCT查连通块大小啊.果断弃了 有加边和删边,还跟连通性有关,于是开始yy ...

  7. 杭电 HDU ACM 2795 Billboard(线段树伪装版)

    Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  8. [THUSC2017]大魔法师:线段树

    分析 在线段树上用\(4 \times 4\)的矩阵打标记. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(register int ...

  9. nyoj--1185--最大最小值(线段树)

    最大最小值 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 给出N个整数,执行M次询问. 对于每次询问,首先输入三个整数C.L.R: 如果C等于1,输出第L个数到第R个数 ...

  10. Buy Tickets(线段树单点更新,逆向思维)

    题目大意:有n个的排队,每一个人都有一个val来对应,每一个后来人都会插入当前队伍的某一个位置pos.要求把队伍最后的状态输出. 个人心得:哈哈,用链表写了下,果不其然超时了,后面转念一想要用静态数组 ...

随机推荐

  1. [Go] 注意 go build -o <output> 选项的准确含义

    -o <output> 选项强制执行把构建的可执行文件写入到目标文件或者目标目录中. 如果 output 是已存在的目录,那么所有构建好的文件都将写入到该目录中. 注意:如果目录不存在的话 ...

  2. dotnet 6 在 win7 系统 AES CFB 抛出不支持异常

    本文记录在 win7 系统上调用 AES 加密时,采用 CFB 模式,可能抛出 CryptographicException 异常 可以看到抛出的异常提示是 System.Security.Crypt ...

  3. dotnet core 不自动从 https 到 http 的 302 重定向

    本文记录一个已知问题,或者准确来说是设计如此的行为,在 dotnet core 下,无论是 dotnet core 3.1 还是 dotnet 5 或 dotnet 6 或 dotnet 7 等,如果 ...

  4. Golang 开发常用代码片段

    Struct to JsonString type BaseRequest struct { httpMethod string domain string path string params ma ...

  5. 显示器AVG、DVI、HDMI、DisplayPort、Type-C、雷电接口

    在近十年的发展,显示设备的接口发生了巨大的改变.以前使用比较多的是蓝色VGA接口,接著出现了白色的DVI接口,当遇到不同接口时,还得买转接头进行转接.后来,又有了HDMI等接口,现在则出现DP和USB ...

  6. 【漏洞分析】HPAY 攻击事件分析

    背景 造成本次攻击的原因是关键函数的鉴权不当,使得任意用户可以设置关键的变量值,从而导致攻击的发生. 被攻击合约:https://www.bscscan.com/address/0xe9bc03ef0 ...

  7. MindSponge分子动力学模拟——自定义控制器(2024.05)

    技术背景 分子动力学模拟中的控制器(Controller)可以被用于修改模拟过程中的原子坐标和原子速度等参量,从而达到控制系统特定参量的目的.例如控温器可以用于实现NVT系综,控压器可用于实现NPT系 ...

  8. 鸿蒙HarmonyOS实战-Stage模型(AbilityStage组件容器)

    前言 组件容器是一种用于管理和组织组件的工具或环境.它可以提供一些基本的功能,如组件的注册.创建.销毁和查找.组件容器通常会维护一个组件的依赖关系,并负责将这些依赖注入到组件中.它还可以提供一些其他的 ...

  9. MindSponge分子动力学模拟——体系控制(2024.05)

    技术背景 在传统的分子动力学模拟软件中,对于分子体系的控制,例如控制体系的相对位置亦或是绝对位置,通常都是通过施加一些约束算法来实现的.例如用于限制化学键的LINCS算法,又比如水分子体系非常常用的S ...

  10. rocketmq 搭建配置

    broker组1: # NameServer地址 namesrvAddr=192.168.1.100: 9876;192.168.1.101: 9876 # 集群名称 brokerClusterNam ...