更新地址:传送门

---

权值线段树

所谓权值线段树,就是一种维护而非下标的线段树,我个人倾向于称呼它为值域线段树。

举个栗子:对于一个给定的数组,普通线段树可以维护某个子数组中数的和,而权值线段树可以维护某个区间内数组元素出现的次数。

在实现上,由于值域范围通常较大,权值线段树会采用离散化或动态开点的策略优化空间。

更新操作:

更新的时候,我们向线段树中插入一个值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,大致题意是给一棵二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少。

由于左右儿子的交换不会影响更上层的值,所以在每次合并的时候直接统计即可。

权值线段树&线段树合并的更多相关文章

  1. HihoCoder1576 子树中的最小权值( dfs序 +线段树 || 树剖)

    给定一棵N个节点的树,编号1~N.其中1号节点是根,并且第i个节点的权值是Vi. 针对这棵树,小Hi会询问小Ho一系列问题.每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多少.为 ...

  2. 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树

    [BZOJ3065]带插入区间K小值 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理 ...

  3. BZOJ4771七彩树——可持久化线段树+set+树链的并+LCA

    给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节 点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义dept ...

  4. BZOJ3110 K大数查询 【线段树 + 整体二分 或 树套树(非正解)】

    Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位 ...

  5. 97: cf 983E 倍增+树套树

    $des$一棵 $n$ 个点的树,树上有 $m$ 条双向的公交线路,每条公交线路都在两个节点之间沿最短路径往返.$q$ 次询问从一个点要到达另一个点,在只坐公交的情况下,至少需要坐几辆公交车:或者判断 ...

  6. B20J_2733_[HNOI2012]永无乡_权值线段树合并

    B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...

  7. 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并

    题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...

  8. [bzoj 2733]启发式合并权值线段树

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 平衡树待学习.从一个博客学到了合并权值线段树的姿势:http://blog.csdn ...

  9. 【bzoj4719】[Noip2016]天天爱跑步 权值线段树合并

    题目描述 给出一棵n个点的树,以及m次操作,每次操作从起点向终点以每秒一条边的速度移动(初始时刻为0),最后对于每个点询问有多少次操作在经过该点的时刻为某值. 输入 第一行有两个整数N和M .其中N代 ...

  10. 【bzoj2212】[Poi2011]Tree Rotations 权值线段树合并

    原文地址:http://www.cnblogs.com/GXZlegend/p/6826614.html 题目描述 Byteasar the gardener is growing a rare tr ...

随机推荐

  1. 《Spring技术内幕》笔记-第二章 IoC容器的实现

    简单介绍 1,在Spring中,SpringIoC提供了一个主要的JavaBean容器.通过IoC模式管理依赖关系.并通过依赖注入和AOP切面增强了为JavaBean这样子的POJO提供事务管理,生命 ...

  2. bzoj 4025 二分图 分治+并查集/LCT

    bzoj 4025 二分图 [题目大意] 有n个点m条边,边会在start时刻出现在end时刻消失,求对于每一段时间,该图是不是一个二分图. 判断二分图的一个简单的方法:是否存在奇环 若存在奇环,就不 ...

  3. multiple web application host under the same website on IIS (authentication mode)

    第一种方式,修改forms的name how to set the forms authentication cookie path assume you have already solved th ...

  4. hibernate初步2

    Hibernate级联设计 数据库表之间的关系(主要关系有一对多.一对一.多对多)主要是从如下三个方面体现出来: 1.表体设计 2.实体类的设计 3.配置文件 以下是一些重要级联设计参数属性介绍: c ...

  5. Java 解析Json数据

    Json格式字符串{success:0,errorMsg:"错误消息",data:{total:"总记录数",rows:[{id:"任务ID" ...

  6. Blender插件加载研究

    目标 [x] 解析Blender插件代码加载原理, 为测试做准备 结论 采用方法3的方式, 可以在测试中保证重新加载子模块, 是想要的方式, 代码如下: _qk_locals = locals() d ...

  7. Java中数组要点总结

    1.数组是基本数据类型和字符串类型的容器(引用数据类型),而集合是类数据类型的容器: 2.数组定义的格式: (1)一般格式: 元素类型[] 数组名 = new 元素类型[元素个数或者数组长度]: 其中 ...

  8. jQuery考试之错题分析

    获取元素范围大小顺序依次为: $(#one).siblings("div")>$("#one~div")>$("#one +div&quo ...

  9. http接口 两种调用http接口的方法

    import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.NameValuePair; ...

  10. windows 装XP系统

    笔记本型号:HPCQ40-506AX 1.在BIOS中更改启动顺序:将USB设为第一启动项2.插入装有PE系统的USB设备3.开机后一直按F124.到达选择系统界面,目前我的HPCQ40用其他系统进去 ...