权值线段树&线段树合并
更新地址:传送门
---
权值线段树
所谓权值线段树,就是一种维护值而非下标的线段树,我个人倾向于称呼它为值域线段树。
举个栗子:对于一个给定的数组,普通线段树可以维护某个子数组中数的和,而权值线段树可以维护某个区间内数组元素出现的次数。
在实现上,由于值域范围通常较大,权值线段树会采用离散化或动态开点的策略优化空间。
更新操作:
更新的时候,我们向线段树中插入一个值v,那么所有包含v的区间值都需要+1。(每个节点维护对应区间中出现了多少个数)
- int update (long long v,long long l,long long r,int pos) { // 插入v,当前区间为[l,r]。
- if (!pos) pos=++tot_node;
- // 如果该节点不存在,则新建节点。
- if (l<=v&&v<=r) {
- // 如果当前区间包含插入值。
- tree[pos].val++;
- // 出现次数+1。
- if (l==r) return pos;
- // 如果递归到叶子节点,退出。
- }
- long long mid=(l+r)>>;
- if (v<=mid) tree[pos].ls=update(v,l,mid,tree[pos].ls);
- else tree[pos].rs=update(v,mid+,r,tree[pos].rs);
- // 判断插入值是在当前区间的哪一半。
- pushup(pos);
- // 回溯。
- return pos;
- }
查询操作:
查询操作类似二叉树。
- 1 long long query (long long l,long long r,long long L,long long R,int pos) { // 查询区间[L,R]中数字的数量,当前区间为[l,r]。
- 2 if (!pos) return 0;
- 3 // 如果该节点不存在,必然没有到达过。
- 4 if (L<=l&&r<=R) {
- 5 // 如果当前区间属于查询区间。
- 6 return tree[pos].val;
- 7 // 直接返回区间中数字的数量。
- 8 }
- 9 long long mid=(l+r)>>1,ans=0;
- 10 if (L<=mid) ans+=query(l,mid,L,R,tree[pos].ls);
- 11 if (mid<R) ans+=query(mid+1,r,L,R,tree[pos].rs);
- 12 // 统计区间和。
- 13 return ans;
- 14 }
练习题:
作为练习模板,可以考虑逆序对。大体思路是每次查询a[i]+1~n的元素个数。
线段树合并
所谓线段树合并,就是通过将合并两颗线段树获得信息,其正确性由线段树的稳定结构保证。
线段树合并通常是一个自底向上的过程,在深搜的途中将子节点的树合并到父节点上,从而实现对父节点值的统计。
线段树合并的复杂度是$nlogn$,比启发式合并少一个$logn$。
不难发现,如果按照线段树合并的原始思想直接在每一个需要遍历的节点上都单独建立一个线段树肯定会爆空间。在这里可以使用被称为“回收内存”的方法:由于在合并之后子节点的信息已经归入父节点,所以子节点没有用处,那么可以将其所有节点回收丢入一个内存池,往后更新的时候可以从内存池里取节点而非新建节点。
回收内存:
- inline int newId () {
- if (pool_top) return mempool[pool_top--];
- return ++tot_node;
- }
- inline void killId (int &x) {
- mempool[++pool_top]=x;
- tree[x].ls=tree[x].rs=tree[x].val=;
- x=;
- }
合并操作:
合并操作与左偏树的合并有一点像,就是递归合并每一个节点。
- int merge (int l,int r,int x,int y) {
- if (!x||!y) return x+y;
- int now=newId(),mid=(l+r)>>;
- if (l==r) {
- tree[now].val=tree[x].val+tree[y].val;
- } else {
- tree[now].ls=merge(l,mid,tree[x].ls,tree[y].ls);
- tree[now].rs=merge(mid+,r,tree[x].rs,tree[y].rs);
- tree[now].val=tree[tree[now].ls].val+tree[tree[now].rs].val;
- }
- killId(x),killId(y);
- return now;
- }
练习题:
可以考虑做一下Tree Rotation,大致题意是给一棵二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少。
由于左右儿子的交换不会影响更上层的值,所以在每次合并的时候直接统计即可。
权值线段树&线段树合并的更多相关文章
- HihoCoder1576 子树中的最小权值( dfs序 +线段树 || 树剖)
给定一棵N个节点的树,编号1~N.其中1号节点是根,并且第i个节点的权值是Vi. 针对这棵树,小Hi会询问小Ho一系列问题.每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多少.为 ...
- 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树
[BZOJ3065]带插入区间K小值 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理 ...
- BZOJ4771七彩树——可持久化线段树+set+树链的并+LCA
给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节 点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义dept ...
- BZOJ3110 K大数查询 【线段树 + 整体二分 或 树套树(非正解)】
Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位 ...
- 97: cf 983E 倍增+树套树
$des$一棵 $n$ 个点的树,树上有 $m$ 条双向的公交线路,每条公交线路都在两个节点之间沿最短路径往返.$q$ 次询问从一个点要到达另一个点,在只坐公交的情况下,至少需要坐几辆公交车:或者判断 ...
- B20J_2733_[HNOI2012]永无乡_权值线段树合并
B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...
- [bzoj 2733]启发式合并权值线段树
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 平衡树待学习.从一个博客学到了合并权值线段树的姿势:http://blog.csdn ...
- 【bzoj4719】[Noip2016]天天爱跑步 权值线段树合并
题目描述 给出一棵n个点的树,以及m次操作,每次操作从起点向终点以每秒一条边的速度移动(初始时刻为0),最后对于每个点询问有多少次操作在经过该点的时刻为某值. 输入 第一行有两个整数N和M .其中N代 ...
- 【bzoj2212】[Poi2011]Tree Rotations 权值线段树合并
原文地址:http://www.cnblogs.com/GXZlegend/p/6826614.html 题目描述 Byteasar the gardener is growing a rare tr ...
随机推荐
- poj3041——最小点覆盖
Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N g ...
- 【BZOJ 1602】 牧场行走
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1602 [算法] 倍增求LCA [代码] #include<bits/stdc+ ...
- B1045 糖果传递 数学
糖果传递,一开始就想到了n^2的模拟贪心算法,但是一看,数据范围太大,好像只有O(N)能过...没啥方法,只好看题解,之后发现,woc,还有这种操作? 这个题直接可以用数学证明... 证明如下: 首先 ...
- 洛谷P3809 后缀数组模板
题目:https://www.luogu.org/problemnew/show/P3809 刚学了后缀数组,看人家手写演示了半天,大概明白了过程,但完全写不出来代码: 于是借鉴了许多,不过都差不多, ...
- 什么是 less? 如何使用 less?
什么是 Less? Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量.混合(mixin).嵌套.函数等功能,让 CSS 更易编写.维护等. 本质上,Less 包含一套自定义 ...
- 洛谷P2916 [USACO08NOV]为母牛欢呼(最小生成树)
P2916 [USACO08NOV]为母牛欢呼Cheering up the C… 题目描述 Farmer John has grown so lazy that he no longer wants ...
- Serializable资料整理
1. 序列化 简单的说就是为了保存 内存中各种对象的状态(是实例变量,不是方法),并且可以把保存的对象读取出来. 虽然保存 object states的方法很多,但是Java提供了一种保存对象状态的机 ...
- Django学习案例一(blog):六. 开发博客内容页面
目标:某条博客具体内容的展示,可返回博客主页面,可进行评论. 1. 编辑路由 一篇博客,要将其找出来,就需要有一个唯一的标识.Django 的模型中默认有一个唯一的且未自增长的主键,即 id 字段.我 ...
- vue.js $set的使用 数组
[javascript] view plain copy <!DOCTYPE html> <html lang="en"> <head> < ...
- telerik:RadAsyncUpload 使用 时不执行上传事件的解决办法AsyncUpload1_FileUploaded(object sender, FileUploadedEventArgs e)
一般是因为web.config没有配置的原因! 只要在<handlers>下加上 <add name="Telerik.Web.UI.WebResource" v ...