树套树Day2
滚回来更新,,,
在Day1我们学了最基本的线段树套平衡树
Day2开始我们要学习一些黑科技
(所以很大概率会出现Day3 w
1.线段树上的黑科技
这一段我们分几项来讲
1.权值线段树
权值线段树以权值为下标建树(就像求逆序对时用的树状数组),一开始所有节点都为0,通过线段树的区间极值,区间和来表示“这个区间上有多少个数”等信息。
下面这个代码并没有离散化因为我懒得写↓
#include <iostream>
#include <cstdio> using namespace std; const int maxn = ; struct Node{
int l,r;
long long tot;
} tree[maxn*]; void build(int l,int r,int o)
{
tree[o].l=l;
tree[o].r=r;
if(tree[o].l==tree[o].r) return ;
int mid=(tree[o].l+tree[o].r)>>;
build(l,mid,o<<);
build(mid+,r,o<<|);
} void push_up(int o)
{
tree[o].tot=tree[o<<].tot+tree[o<<|].tot;
} void update(int o,int x)
{
if(tree[o].l==x && tree[o].l==tree[o].r)
{
tree[o].tot++;
return ;
}
int mid=(tree[o].l+tree[o].r)>>;
if(x<=mid) update(o<<,x);
if(x>mid) update(o<<|,x);
push_up(o);
} long long getans(int o,int l,int r)
{
if(tree[o].l>r || tree[o].r<l) return ;
if(tree[o].l==l && tree[o].r==r) return tree[o].tot;
int mid=(tree[o].l+tree[o].r)>>;
if(r<=mid) return getans(o<<,l,r);
if(l>mid) return getans(o<<|,l,r);
return getans(o<<,l,mid)+getans(o<<|,mid+,r);
} int main()
{
int n;
scanf("%d",&n);
build(,maxn,);
long long ans=;
for(int i=;i<=n;i++)
{
int x;
scanf("%d",&x);
ans+=getans(,x+,maxn);
update(,x);
}
printf("%lld",ans);
}
求逆序对
2.标记永久化
线段树的pushup和pushdown操作有时候实现代价很大,我们能不能不用这两个东西呢?
可以。具体做法就是每个节点记一个sum记一个add,
修改的时候:
1.当目前询问区间与当前区间完全重合的时候,更新add的值,返回。
2.在一路下来的时候把所有经过的区间(相当于包含询问区间的区间)的sum加上此次修改所产生的影响 v*(xr-xl+1)。
(注意完全重合之后就返回了,也就是说下面的部分的影响还没有更新。)
查询的时候:
由于上面的更新没有对下面产生影响,所以我们需要一路累加add,直到目前询问区间与当前区间完全重合的时候,答案为sum+add*区间长度
注意累加add不用累加上完全重合的区间的add,因为它已经在修改的时候对sum进行更新了
#include<iostream>
#include<cstdio>
#include<cstring>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 201000
using namespace std;
int n,m;
int sum[N*],add[N*];
int a[N];
void build(int l,int r,int rt){
if(l==r){
sum[rt]=a[l];return;
}
int mid=(l+r)>>;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
sum[rt]=sum[rt<<]+sum[rt<<|];
}
void update(int rt,int l,int r,int v,int xl,int xr){
sum[rt]+=v*(xr-xl+);
if(l==xl&&r==xr){
add[rt]+=v; return;
}
int mid=(l+r)>>;
if(xr<=mid) update(rt<<,l,mid,v,xl,xr);
else{
if(xl>mid) update(rt<<|,mid+,r,v,xl,xr);
else update(rt<<,l,mid,v,xl,mid),update(rt<<|,mid+,r,v,mid+,xr);
}
}
int query(int rt,int ad,int l,int r,int xl,int xr){
if(xl==l&&xr==r){
return sum[rt]+ad*(xr-xl+);
}
int mid=(l+r)>>;
if(xr<=mid) return query(rt<<,ad+add[rt],l,mid,xl,xr);
else{
if(xl>mid) return query(rt<<|,ad+add[rt],mid+,r,xl,xr);
else return query(rt<<,ad+add[rt],l,mid,xl,mid)+query(rt<<|,ad+add[rt],mid+,r,mid+,xr);
}
}
int main(){
scanf("%d%d",&n,&m);
pos(i,,n) scanf("%d",&a[i]);
build(,n,);
pos(i,,m){
int opt;scanf("%d",&opt);
int x,y;scanf("%d%d",&x,&y);
if(opt==){
int k;scanf("%d",&k);
update(,,n,k,x,y);
}
else printf("%d\n",query(,,,n,x,y));
}
return ;
}
标记永久化
这个做法在主席树,树套树中很有用
3.主席树
又称函数式线段树,具体就是有多个版本的线段树,可以支持“回溯”到之前的某个版本,网上介绍很多,这里不多说了。
2.二维线段树
也就是线段树套线段树,对于线段树的每个区间维护一个线段树,这样就可以求矩形和/矩形极值了。具体个人有个人的写法。
3.动态开节点
有的时候有些节点你只是放一个标记在那里,不需要实际操作,你就可以开一个“大节点”表示那一块不用实际操作的节点,当需要操作的时候再从那个“大节点”里搞出几个"小节点"来操作。
这样可以避免MLE
具体可以见NOIp2017D2T3列队的平衡树写法,我的blog里应该有
4.怎样的两棵树可以套
数据结构的嵌套,当你对数据结构掌握得很熟练的时候其实自然就明白了。其实树套树不过是用“内层树”维护“外层树”节点上的信息。(一般“外层树”节点上的信息是用数/数组维护的)
而外层树的结构稳定,不会出现Splay/Treap/AVL这种东西
而且很多可以顶一层数据结构的东西其实也可以嵌套
比如CDQ套某某某,替罪羊套某某某
树套树Day2的更多相关文章
- BZOJ 3110: [Zjoi2013]K大数查询 [树套树]
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6050 Solved: 2007[Submit][Sta ...
- BZOJ4170 极光(CDQ分治 或 树套树)
传送门 BZOJ上的题目没有题面-- [样例输入] 3 5 2 4 3 Query 2 2 Modify 1 3 Query 2 2 Modify 1 2 Query 1 1 [样例输出] 2 3 3 ...
- bzoj3262: 陌上花开(树套树)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- bzoj3295: [Cqoi2011]动态逆序对(树套树)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- BZOJ 3110 k大数查询 & 树套树
题意: 有n个位置,每个位置可以看做一个集合,现在要求你实现一个数据结构支持以下功能: 1:在a-b的集合中插入一个数 2:询问a-b集合中所有元素的第k大. SOL: 调得火大! 李建说数据结构题能 ...
- BZOJ 3110 树套树 && 永久化标记
感觉树套树是个非常高深的数据结构.从来没写过 #include <iostream> #include <cstdio> #include <algorithm> ...
- 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树套树)
http://www.lydsy.com/JudgeOnline/problem.php?id=1901 这题调了我相当长的时间,1wa1a,我是第一次写树套树,这个是树状数组套splay,在每个区间 ...
- hdu 4417 Super Mario/树套树
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 题意很简单,给定一个序列求一个区间 [L, R,]中小于等于H的元素的个数. 好像函数式线段树可 ...
- Uva 3767 Dynamic len(set(a[L:R])) 树套树
Dynamic len(set(a[L:R])) Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://uva.onlinejudge.org/in ...
随机推荐
- iOS 生命周期 -init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear、viewDidDisappear 区别和用途
iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...
- lua(简单的传参)
#include <iostream> #include <string.h> extern "C" { /*头文件lua.h定义了Lua提供的基础函数,包 ...
- 【BZOJ3791】作业 DP
[BZOJ3791]作业 Description 众所周知,白神是具有神奇的能力的.比如说,他对数学作业说一声“数”,数学作业就会出于畏惧而自己完成:对语文作业说一声“语”,语文作业就会出于畏惧而自己 ...
- 【python】-- paramiko、跳板机(堡垒机)
paramiko Python的paramiko模块,该模块用于连接远程服务器并执行相关命令,常用于作批量管理使用 一.下载: pip3 install paramiko 源码:查看 二.parami ...
- 【Android】开发优化之——调优工具:dump hprof file 查看内存情况,找到内存泄露
虽说知道一般性的开发android应用须要注意的问题,但是也有水平參差不齐的情况.特别是维护代码,假设内存占用大,内存溢出严重,又怎么解决呢? -- 通过DDMS把heap抓出来分析 1.打开DD ...
- zabbix监控入门初步
1.Zabbix是什么? Zabbix是一个基于Web界面的分布式系统监控的企业级开源软件.可以监视各种系统与设备的参数,保障服务器及设备的安全运营. 2.Zabbix的功能和特性 (1)安装与配置简 ...
- Facial landmark detection - 人脸关键点检测
Facial landmark detection (Facial keypoints detection) OpenSourceLibrary: DLib Project Home: http: ...
- mysql 主从,主主,主主复制时的主键冲突解决
原理:slave 的i/o thread ,不断的去master抓取 bin_log, 写入到本地relay_log 然后sql thread不断的更新slave的数据 把主服务器所有的数据复制给从服 ...
- mysql备份,知识点
1.mysql错误日志 show variables like '%log_error%'; my.cnf中log-error=/tmp/SZDB.err 开启 tail -f 错误日志 观察mys ...
- 算法(Algorithms)第4版 练习 1.5.1
id数组的变化情况: 0 1 2 3 4 5 6 7 8 9 10 components 9 0 0 1 2 3 4 5 6 7 8 0 9 components 3 4 0 1 2 4 5 6 7 ...