7.30集训——线段树
目录
李超线段树
动态开点线段树
可持久化线段树(主席树)
启发式合并
luogu P3372线段树模板
#include<bits/stdc++.h>
#define MAXN 1000001
#define ll long long
using namespace std;
unsigned ll n,m,a[MAXN],ans[MAXN<<2],tag[MAXN<<2];
inline ll ls(ll x)
{return x<<1;
}
inline ll rs(ll x)
{return x<<1|1;
}
void scan()
{cin>>n>>m;for(ll i=1;i<=n;i++){scanf("%lld",&a[i]);}
}
inline void push_up(ll p)
{ans[p]=ans[ls(p)]+ans[rs(p)];
}
void build(ll p,ll l,ll r)
{tag[p]=0;if(l==r){ans[p]=a[l];return ;}ll mid=(l+r)>>1;build(ls(p),l,mid);build(rs(p),mid+1,r);push_up(p);
}
inline void f(ll p,ll l,ll r,ll k)
{tag[p]=tag[p]+k;ans[p]=ans[p]+k*(r-l+1);
}
inline void push_down(ll p,ll l,ll r)
{ll mid=(l+r)>>1;f(ls(p),l,mid,tag[p]);f(rs(p),mid+1,r,tag[p]);tag[p]=0;
}
inline void update(ll nl,ll nr,ll l,ll r,ll p,ll k)
{if(nl<=l&&r<=nr){ans[p]+=k*(r-l+1);tag[p]+=k;return ;}push_down(p,l,r);ll mid=(l+r)>>1;if(nl<=mid){update(nl,nr,l,mid,ls(p),k);}if(nr>mid) {update(nl,nr,mid+1,r,rs(p),k);}push_up(p);
}
ll query(ll q_x,ll q_y,ll l,ll r,ll p)
{ll res=0;if(q_x<=l&&r<=q_y){return ans[p];}ll mid=(l+r)>>1;push_down(p,l,r);if(q_x<=mid){res+=query(q_x,q_y,l,mid,ls(p));}if(q_y>mid) {res+=query(q_x,q_y,mid+1,r,rs(p)); }return res;
}
int main()
{ll a1,b,c,d,e,f;scan();build(1,1,n);while(m--){scanf("%lld",&a1);switch(a1){case 1:{scanf("%lld%lld%lld",&b,&c,&d);update(b,c,1,n,1,d);break;}case 2:{scanf("%lld%lld",&e,&f);printf("%lld\n",query(e,f,1,n,1));break;}}}return 0;
}
洛⾕ P3801 红⾊的幻想乡
n*m(n, m <= 105)的矩形区域中,进⾏如下两个操作: 1 x y : 蕾⽶莉亚站在坐标(x,y)的位置向四个⽅向释放⽆限的 红雾,当两个红雾相遇在同⼀点,则会沉降消失。 2 x1 y1 x2 y2 : 询问左上点为(x1,y1),右下点为(x2,y2)的矩 形范围内,被红雾遮盖的地区的数量
- ⼀块n*m⼦矩阵中,施加 过红雾的⾏数为x、列数为y,则相遇抵消的点数 为x*y, 则红雾覆盖的点 数为 。
洛⾕ P2824 [HEOI2016/TJOI2016]排序
给出⼀个1到n的全排列,现在对这个全排列序列进⾏m次局部排序, 排序分为两种:
1:(0,l,r)表示将区间[l,r]的数字升序排序;
2:(1,l,r)表示将区间[l,r]的数字降序排序。
最后询问第q位置上的数字。
- 二分q点的答案ans,原序列中小于等于ans的看成0,大于ans的看成1,这样区间排序就变成区间求和然后区间修改了
洛⾕ P4198 楼房重建
小 A 的楼房外有一大片施工工地,工地上有 N 栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。
为了简化问题,我们考虑这些事件发生在一个二维平面上。小 A 在平面上 (0,0)(0,0)(0,0) 点的位置,第 iii 栋楼房可以用一条连接 (i,0) 和 的线段表示,其中 为第 i 栋楼房的高度。如果这栋楼房上任何一个高度大于 0 的点与 (0,0) 的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。
施工队的建造总共进行了 M 天。初始时,所有楼房都还没有开始建造,它们的高度均为 0。在第 i 天,建筑队将会将横坐标为 的房屋的高度变为 (高度可以比原来大—修建,也可以比原来小—拆除,甚至可以保持不变—建筑队这天什么事也没做)。请你帮小 A 数数每天在建筑队完工之后,他能看到多少栋楼房?
- 首先,把所有的高度a[i]除以坐标i,得到从(0,0)望过去的直线斜率,判断楼与楼是否遮挡直接比较斜率大小即可
- ans[k]表示节点k区间中的“单调递增序列”度(从左到右能看到的楼的数量)
- 考虑由左右儿子的ans求出父亲节点的ans
- 左儿子的ans都可以对父亲节点的ans做出贡献,而右儿子的ans则可能已经被左儿子中的楼遮挡,设左儿子的最大斜率为h,若能用求出节点k区间中大于h的楼的“单调递增序列”度,则
- 那么如何写这个calc(k,h)函数呢?还是分情况讨论
- 若左子树中没有大于h的,则返回
- 若左子树中有大于h的,则全部对有贡献,右子树对ans[k]贡献的答案中都是大于h的楼房,则这个答案全部对有贡献,返回的就是
- 这样调用一次函数复杂度是,总共调用次,总复杂度
李超线段树
用于解决区间添加一次函数、单点查询所有一次函数最大值的问题
洛⾕ P4097 [HEOI2013]Segment
要求在平⾯直⻆坐标系下维护两个操作:
- 在平⾯上加⼊⼀条线段。记第 i 条被插⼊的线段的标号为 i
- 给定⼀个数 k, 询问与直线 x = k 相交的线段中,交点最靠上的线段的编号。
- 维护一个线段树,线段树每个节点维护对应区间的“优势线段”,即区间中点对应值最大的线段
- 当在一个节点上添加一条线段时,分情况讨论:
- 当新线段完全被原优势线段覆盖时,新线段没用,不做修改
- 当新线段完全覆盖原优势线段时,原优势线段没用,将整个子树优势线段改为新线段
- 当两者有交点时,新优势线段为两者中中点对应值较大的一条,另一条递归添加到交点所在的一侧儿子中
- 写着写着可以发现——这个标记可以永久化
- 标记永久化:标记不进行下传,查询某一点时,取根到该叶子路径上所有标记的最优值
动态开点线段树
我们来观察一下普通线段树的左儿子和右儿子的表示方法
左儿子:p<<1
右儿子:p<<1|1
这样,虽然我们可以直接算出左右儿子,比较方便,但是,这样也浪费了大量的空间
链式储存法:即对一个节点维护其左右儿子的编号,指向它的左右儿子,这样,只有当访问某个节点时,我们才需要建立该节点,减小了空间
//单点修改
int insert(int k,int l,int r,int x)
{if(!k){k=++tot;}if(l==r){return sum[k]=a[l],k;} if(x<=mid){ls[k]=insert(ls[k],l,mid,x);}else{re[k]=insert(re[k],mid+1,r,x);}sum[k]=sum[ls[k]]+sum[rs[k]];return k;
}
//区间查询
int query(int k,int l,int r,int x,int y)
{if(x<=l&&r<=y){return sum[k]; }int mid=(l+r)>>1,res=0;if(x<=mid){res+=query(ls[k],l,mid,x,y);}if(y>mid){res+=query(rs[k],mid+1,r,x,y);}return res;
}
可持久化线段树(主席树)
对于一个经过m次修改操作的线段树,可持久化线段树能维护其所有的m个历史版本
我们发现,每次修改只会修改线段树中的个节点,因此我们可以只对这个点开新节点,其余沿用旧树上的点
//单点修改
void update(int &o,int l,int r,int last,int p,int v)
{o=++tot;ls[o]=ls[last];rs[o]=rs[last];if(l==r){a[o]=v;return ; } int m=(l+r)>>1;if(p<=m){update(ls[o],l,m,ls[last],p,v);}else{update(rs[o],m+1,r,rs[last],p,v);}
}
查询无区别
静态区间第k小
给定n个数的序列,m次查询区间[l,r]的第k小值,n,m<=2e5
权值数组:一个数组a满足a[i]值为i的数的个数
权值线段树:维护权值数组的线段树
假如我们获得了[l,r]的权值线段树,查询时若左儿子区间和>=k则递归左儿子,若<k则递归右儿子即可
如何求[l,r]的权值线段树
可持久化线段树维护的权值线段树
即为[l,r]的权值线段树
//查询
int query(int s,int t,int l,int r,int x)
{if(l==r){return l;}int cnt=sum[ls[t]]-sum[ls[s]];if(cnt>=x){return query(ls[s],ls[t],l,mid,x);} else{return query(rs[s],rs[t],mid+1,r,x-cnt);}
}
将两棵动态开点线段树合并到一起(对应位置相加)
如果一方对应位置没有点的话就用另一方的,都有就递归下去
复杂度
//合并
int merge(int p1,int p2,int l,int r)//表示将树p2的信息合并到树p1上
{if(!p1||!p2){return p1+p2; } if(l==r){s[p1]=s[p1]+s[p2];return p1;}int mid=(l+r)>>1;ls[p1]=merge(ls[pl],ls[p2],l,mid);rs[p1]=merge(rs[p1],rs[p2],mid+1,r);s[p1]=s[ls[pl]]+s[rs[pl]];return p1;
}
启发式合并
定义:将n个集合,合并集合A,B时,将较小的集合中的元素一个个插入到较大集合中,单次复杂度为
复杂度:
证明:每个数在跟比它所在集合更大的集合合并时会产生1的贡献,所在集合大小至少翻一倍,最多产生次贡献
黑科技
用于解决一些插入容易实现而删除难以实现的问题
用一个的代价将问题转化成只有插入
线段树分治
一个n个节点的图,m次操作,每次插入一条边,删除一条边。Q次查询,每次查询图是不是二分图。n,m<=1e5
- 线段树分治实际上是一种维护时间区间的数据结构,同样是利用线段树的分治性,让复杂度保证在了级别
- 开一棵维护操作时间的线段树,我们考虑如何维护一个操作影响的时间区间,假设一个操作影响的时间时[L,R],将其呈现在线段树上找这个询问所在时间点,把根到叶子路径上的所有影响计算一遍,就能得出这个询问的答案
- 每次递归整棵线段树,到达一个节点时执行该节点上的所有操作,离开时撤销
7.30集训——线段树相关推荐
- 2018石中大集训线段树总结.。。。
8/1 线段树练习总结--谢鹏宇 PS:题目见底部... A - I Hate It 就是一道模板题,但是还是提交了很多次,评测机可能对STD的max函数有点误解,用STD的就会错,然后自己手写了一个 ...
- 8.5 暑假集训——线段树篇
是小潘学姐讲的这章,题目给的有些难度,很多没做出来,找了别的博客讲解的题刷 http://blog.csdn.net/metalseed/article/details/8039326 其中 hdu1 ...
- 数据结构二之线段树Ⅰ——Count Color,Hotel,Transformation,Tree Generator™
普通的下标线段树 Count Color Hotel Transformation Tree Generator™ Count Color POJ2777 查询区间内颜色种类数,观察到颜色种类数只有3 ...
- 暑期集训5:并查集 线段树 练习题F: HDU - 1166
2018学校暑期集训第五天--并查集 线段树 练习题F -- HDU - 1166 敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A ...
- 暑期集训5:并查集 线段树 练习题G: HDU - 1754
2018学校暑期集训第五天--并查集 线段树 练习题G -- HDU - 1754 I Hate It 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让 ...
- 暑期集训5:并查集 线段树 练习题B: HDU - 1213
2018学校暑期集训第五天--并查集 线段树 练习题B -- HDU - 1213 How Many Tables Today is Ignatius' birthday. He invites ...
- 暑期集训5:并查集 线段树 练习题A: HDU - 1232
2018学校暑期集训第五天--并查集 线段树 练习题A -- HDU - 1232 畅通工程 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅 ...
- P3899 [湖南集训]谈笑风生(线段树合并)
P3899 [湖南集训]谈笑风生 给定一颗以111号节点为根的树,如果a≠ba \neq ba=b,且aaa是bbb的祖先,则aaa比bbb更厉害,如果a≠ba \neq ba=b,且dis( ...
- 【地狱副本】数据结构之线段树Ⅲ——区间最值/赋值/修改/历史值操作(HDU5306,Tyvj 1518,【清华集训2015】V,HDU6315,HDU1828,POJ3162)
文章目录 Gorgeous Sequence Tyvj 1518 CPU监控 [清华集训2015]V Naive Operations Picture Walking Race Gorgeous Se ...
最新文章
- 今天是2013年06月21日,博客之路开始了!
- 坦途与波折:我们需要什么样的人工智能?
- 计算机在识字教学中的应用,【多媒体技术论文】多媒体技术在小学识字教学中的应用(共3090字)...
- Web性能压力测试工具——Siege详解
- python中文编辑器推荐-推荐10款最好的Python开发编辑器
- 9.3 低秩矩阵分解-机器学习笔记-斯坦福吴恩达教授
- 基于matlab的频域辨识,基于Lab VIEW的控制系统频域分析研究
- 什么是 NIO? NIO 和 BIO、AIO 之间的区别是什么?NIO主要用来解决什么问题?
- 非集成搭建wampp环境
- 2019年,区块链不得不知的 9 件大事!
- java反编译有什么用处_Java反编译工具有什么用,Java反编译工具使用解析
- Android: eoeAndroid ~
- 趋势顶底(QSDD)----无未来函数
- 细丝菲涅尔衍射MATLAB,任意孔型菲涅尔衍射matlab仿真.docx
- Spring核心是什么
- SRRC型号核准的一点澄清-- 设备型产品的SRRC是强制性的,但模块型为非强制性的,有条件可参考性
- edge下载网络问题无法下载
- Todo Tree插件配置
- 运行edX Devstack
- 【互动媒体】结课作业第二部分:数据分析、可视化以及几个额外问题