权值线段树&线段树合并
更新地址:传送门
---
权值线段树
所谓权值线段树,就是一种维护值而非下标的线段树,我个人倾向于称呼它为值域线段树。
举个栗子:对于一个给定的数组,普通线段树可以维护某个子数组中数的和,而权值线段树可以维护某个区间内数组元素出现的次数。
在实现上,由于值域范围通常较大,权值线段树会采用离散化或动态开点的策略优化空间。
更新操作:
更新的时候,我们向线段树中插入一个值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 ...
随机推荐
- 自己定义控件-仿iphone之ToggleButton&VoiceSeekBar
由于项目中须要使用开关切换button,和声音滑动控件,可是原生Android5.0版本号以下的控件实在是太挫了.尽管网上已经有非常多关于这两个控件的blog.可是我实在是找不到像iPhone这样简洁 ...
- Golang Template source code analysis(Parse)
This blog was written at go 1.3.1 version. We know that we use template thought by followed way: fun ...
- 一条SQL语句求全年平均值
一年有8760个小时!(才这么点...) 有个气候表,存储了当地从1到8760小时的温度数据.现在,要求全年的温度每天平均值. CREATE TABLE #Climate(h INT ,t DECIM ...
- ASP.NET MVC 客户端验证失败后表单仍然提交问题
客户端验证失败后表单仍然提交问题!导致页面刷新,辛辛苦苦输入的内容荡然无存. 多么奇怪的问题.按道理,验证失败,就应该显示各种错误信息,不会提交表单才对.而现在,错误信息正常显示,但页面却刷新了一遍. ...
- 在Android中创建文件
import java.io.File; import java.io.IOException; import android.app.Activity; import android.os.Bund ...
- django自带url模板标签的使用
django模板中url标签和view中的reverse(博客地址)功能相同,都是通过制定处理视图来返回一个url. 使用方法: {% url userEdit 12 %} 或者 {% url use ...
- codevs1060 搞笑世界杯(概率dp)
1060 搞笑世界杯 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 随着世界杯小组赛的结束,法国,阿根廷等世界 ...
- Python 35 线程(1)线程理论、开启线程的两种方式
一:线程理论 1 什么是线程 进程其实一个资源单位,而进程内的线程才是cpu上的执行单位 线程其实指的就是代码的执行过程2 为何要用线程 线程vs进程 1. 同一进程下的多个线程共享该进程 ...
- 1.ArcGis几何图形之几何计算
/// <summary> /// 检测几何图形A是否包含几何图形B /// </summary> /// <param name="pGeometryA&qu ...
- VMWare linux 打印太多,看不到之前的记录的解决方法总结
1.在命令后面加 | more. 可以每次按空格键或是回车键后翻.2.命令后面加| less ,可以前后翻.3.用重定向到文件 > 文件名,之后慢慢看 ----待补充 ------