线段树

线段树模板

风流意气都作罢 提交于 2019-11-30 01:02:38
线段树----单点、区间加法,单点、区间覆盖,区间最大最小值 线段树基本知识 详解可以看这个:https://www.luogu.com.cn/problemnew/solution/P3372 摘录了一点点。。。 对于每一个子节点而言,都表示整个序列中的一段子区间;对于每个叶子节点而言,都表示序列中的单个元素信息;子节点不断向自己的父亲节点传递信息,而父节点存储的信息则是他的每一个子节点信息的整合。 有没有觉得很熟悉?对,线段树就是分块思想的树化,或者说是对于信息处理的二进制化——用于达到O(logn)O(logn)级别的处理速度,loglog以22为底。(其实以几为底都只不过是个常数,可忽略)。而分块的思想,则是可以用一句话总结为:通过将整个序列分为有穷个小块,对于要查询的一段区间,总是可以整合成kk个所分块与mm个单个元素的信息的并(0<=k,m<=\sqrt{n})(0<=k,m<= n )。但普通的分块不能高效率地解决很多问题,所以作为loglog级别的数据结构,线段树应运而生。 建树过程 void build ( ll rt , ll l , ll r ) { if ( l == r ) { st [ rt ] = a [ l ] ; return ; } ll mid = ( r + l ) >> 1 ; build ( rt << 1 , l , mid ) ;

HDU6703 array (线段树)

吃可爱长大的小学妹 提交于 2019-11-30 00:15:08
题意:长为1e5的全排列 有两个操作 把一个数删掉    询问1,r这个区间内 找到一个数大于等于x 且这个数不等于区间内的所有数 题解:建一颗权值线段树 线段树里存值为i的数在原数组中的坐标 维护坐标的最大值    考虑删除操作 就等于让他的坐标变为n+1 因为答案一定在1-n+1    对于查询操作 等价于找在[x,n]这个权值区间内左边第一个出现的数 且他的坐标是大于r的 #include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; int n, m; int a[MAXN], b[MAXN]; int pos[MAXN << 2]; void pushup(int rt) { pos[rt] = max(pos[rt << 1], pos[rt << 1 | 1]); } void build(int l, int r, int rt) { if(l == r) { pos[rt] = b[l]; return; } int mid = l + r >> 1; build(l, mid, rt << 1); build(mid + 1, r, rt << 1 | 1); pushup(rt); } void update(int k, int l, int r, int rt) { if(l

区间树

回眸只為那壹抹淺笑 提交于 2019-11-29 22:25:46
区间树 注意: 区间树和线段树不一样哦,线段树是一种特殊的区间树。 区间树 : 区间树是在 红黑树基础上 进行扩展得到的支持以 区间为元素 的动态集合的操作,其中每个节点的关键值是区间的左端点。通过建立这种特定的结构,可是使区间的元素的查找和插入都可以在 O(lgn) 的时间内完成。相比于基础的红黑树数据结构,增加了一个 max[x] ,即以 x 为根的子树中所有区间的断点的最大值。逻辑结构如下所示: 区间树具有和红黑树一样的性质,并且区间树的基础操作和红黑树的基础操作一样。 红黑树的性质如下:(一定要牢记哦!) ( 1 )节点要么是红色的,要么是黑色的 ( 2 )根节点是黑色的 ( 3 )每个叶节点(即空节点)是黑色的 ( 4 )若节点是红色的,则它的孩子节点必为黑色 ( 5 )对每个节点,从该节点到它的子孙叶子节点的所有路径上包含相同的黑色节点。 线段树 : 线段树是一种平衡二叉查找树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。主要的处理思想是基于分治的思想。它的逻辑结构如下: 设根节点的区间为 [a,b), 区间长度为 L = b - a ,线段树的性质: ( 1 )线段树是一个平衡树,树的高度为 log(L) ( 2 )线段树把区间上的任意长度为 L 的线段都分成不超过 2log(L) 线段的并 线段树基础存储结构如下:(这里使用数组模拟指针

codeforces 1136E 线段树

早过忘川 提交于 2019-11-29 21:59:10
codeforces 1136E: 题意:给你一个长度为n的序列a和长度为n-1的序列k,序列a在任何时候都满足如下性质,a[i+1]>=ai+ki,如果更新后a[i+1]<ai+ki了,那么a[i+1]=ai+ki 现在给你q次操作 操作1:将位置为pos的元素+x 操作2:询问区间l,r的区间和 题解:非常明显的线段树题,我们不好维护的是,如果更新后,当前数字变大到不满足限制条件时,我后面的元素也要做出相应的更新 那么我们就将a序列先减去k序列,这样的a序列也是满足限制条件了,然后我们记录下k的前缀和的前缀和,避免询问时缺少k的贡献, 数学推导如下 序列a满足单调不减性, 则∑ai 同样满足单调不减性, 当我们对位置为pos的元素进行更新时, 如果后面的元素 a[pos+R]<a[pos],则该元素要被覆盖, 所以我们二分右端点,将区间【pos,R】覆盖为a[pos]+x即可 为了避免重复计算ki对a的贡献所以我们覆盖区间时可以用如下技巧 用c来记录k的前缀和的前缀和 每次覆盖时,我们将区间【l,r】覆盖为(a[pos]+x-k[pos])*(r-l+1)+c[r+1]-c[l] 这样就不会使得k的贡献计算错了 来源: https://www.cnblogs.com/buerdepepeqi/p/11536530.html

NOI 2015 软件包管理器

随声附和 提交于 2019-11-29 21:47:39
洛谷 P2146 [NOI2015]软件包管理器 洛谷传送门 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debian/Ubuntu使用的apt-get,Fedora/CentOS使用的yum,以及OSX下可用的homebrew都是优秀的软件包管理器。 你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B。同时,如果想要卸载软件包B,则必须卸载软件包A。现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包。依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,⋯,Am,其中A1依赖A2,A2依赖A3,A3依赖A4,……,A[m-1]依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。 现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态

HDU 2795(思维+线段树)

谁说胖子不能爱 提交于 2019-11-29 20:55:35
Billboard Time Limit: 20000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 32864 Accepted Submission(s): 13090 Problem Description At the entrance to the university, there is a huge rectangular billboard of size h*w (h is its height and w is its width). The board is the place where all possible announcements are posted: nearest programming competitions, changes in the dining room menu, and other important information. On September 1, the billboard was empty. One by one, the announcements started being put on the billboard. Each announcement is a stripe of

9 16 模拟赛&关于线段树上二分总结

会有一股神秘感。 提交于 2019-11-29 20:38:58
1 考试时又犯了一个致命的错误,没有去思考T2的正解而是去简单的推了一下式子开始了漫漫找规律之路,不应该这样做的 为了得到规律虽然也打了暴力 但是还是打了一些不必要的程序 例如求组合数什么的比较浪费时间了。 考试后在我看来这都是浪费时间了 浪费了我足足1h30min 其实是可以避免的 得不到正解先去看下一道题 都做完了再回来重新审视这道题。 2 T3的正解推得的时间虽然不长但是没有仔细思考自己的做法是否优秀尽管应该是正确的 但是不充足的思考让我的代码变得非常的冗长。 例如 一些区间求和的操作我完全可以直接拿处理好的前缀和后缀和数组求但是我还是写了两个线段树函数求和。明明可以不用线段树O(n)来写代码复杂度会低的很但是我没有充分的思考直接码上了线段树... 当然还是有优点的 T1写完后直接开始对拍了 这一点很好(拍了2万组数据 所以我就没怎么检查 就直接交了。 再论述题解的时候 我希望这套题不仅仅是对考试的思考 还有对线段树的总结我想我应该总结线段树的某些功能是怎么写的了不能每次写的时候都再推一遍。 线段树上二分是一个技巧且比较有用因为其利用本身就是区间二分的形式建的树和本身就支持查询区间最值的特点致使我们寻找某个值比较方便。 这里先给出题目背景 给定一个序列对于询问 x 求整个序列小于x的第一个位置是谁? 这个我们暴力扫其实都可以 但是多次询问呢?把询问离线由大到小的搞,强制在线呢

CF765F Souvenirs 线段树

▼魔方 西西 提交于 2019-11-29 19:12:12
传送门 神仙题 将询问离线然后枚举右端点,维护每一个位置 \(i\) 与其之后的所有位置 \(j\) 的距离最小值然后区间取min。显然这样的做法的最劣复杂度是 \(O(n^2)\) 的,我们需要一些剪枝。 我们考虑对于某一个位置 \(i\) ,在其之后 真正 有可能更新最小值的位置有哪些。如果设序列 \(\{a\}\) 是一个递增序列, \(a_1 > i,val_{a_1} \geq val_i\) ,且每当右端点取到其中的某个 \(a_j\) 时 \(i\) 位置的最小值会进行有效的更新,那么会要满足: \(\forall j \in [1,|a|) , |val_i - val_{a_j}| \geq 2|val_i - val_{a_{j+1}}|\) ,这是因为如果这个条件不满足那么 \(a_j\) 与 \(a_{j+1}\) 的距离会更小,此时对 \(i\) 的更新就是无效的。 不难发现上面的 \(a\) 序列的长度最多只会有 \(log 10^9\) 项,所以我们可以使用线段树找出当右端点移到哪些位置的时候需要修改 \(i\) 位置,然后移动右端点进行更新并统计答案。复杂度 \(O(nlog^2n+qlogn)\) #include<bits/stdc++.h> using namespace std; int read(){ int a = 0; char c =

bzoj4756线段树合并模板

折月煮酒 提交于 2019-11-29 18:38:11
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 100003 using namespace std; int n,a[N],b[N],tot; int head[N]; int tr[N*20],ls[N*20],rs[N*20],root[N],cnt,sz,ans[N]; struct edge { int v,next; }edges[N*2]; void init() { memset(head,-1,sizeof(head)); tot=0; } void add(int x,int y) { edges[tot].next=head[x]; edges[tot].v=y; head[x]=tot++; } void update(int now) { tr[now]=tr[ls[now]]+tr[rs[now]]; } void insert(int &i,int l,int r,int x) { if (l>r) return; i=++sz; if (l==r) { tr[i]=1; return; } int mid=(l+r)/2; if (x<=mid) insert(ls[i],l,mid,x); else

2019-9-14做题记录

旧城冷巷雨未停 提交于 2019-11-29 15:05:14
1、【BZOJ1493】【NOI2007】项链工厂 已经是十二年之前的$NOI$了,现在看来古人们学的东西我都不会。 一个环,每个元素有颜色,六种操作。 $Rotate\ k$:将项链顺时针旋转$k$个单位。即原$i$位置变成现在$i+k$位置。 $Flip$:将项链沿指定对称轴翻转,即将项链的$i$位置和$n+2-i$位置互换。 $Swap\ i\ j$:将项链的$i$位置和$j$位置的颜色互换。 $Paint\ i\ j\ x$:将项链从$i$位置开始,顺时针$j$个长度的区间染成$x$。 $Count$:询问整个项链上颜色块数。 $CountSegment\ i\ j$:询问项链从$i$位置开始,顺时针$j$个长度的区间颜色块数。 这个东西肯定是用$splay$更好维护,但是我非要用线段树。 首先,我们把环变成一条链,$5,6$两个操作显然可以在线段树上直接套用维护颜色块数的方法,当越过终点是再把两个答案合并起来就行了。 $3,4$也很简单,单点修改和区间赋值。 $2$也很简单,向$splay$那样打翻转标记即可,等到查询的时候一条链$pushr$下来。 $1$只是映射关系的改变,我们记录一下,等到查的时候还原回来就可以了。 看了题解,发现$2$假了,因为线段树是不能向平衡树那样随意分离出子树(子区间的),所以维护映射关系的时候乘个负号就行了。 2、【CF666E