线段树

POJ2182 线段树维护区间可用值

时光毁灭记忆、已成空白 提交于 2019-12-13 09:01:40
题意 给你n 下面n - 1个数表示从第2个到第n个——第i个cow前面有多少只编号比它小的cows 问你这n只cows的排列。 思路 线段树维护区间可以用的编号有几个。 从后先前枚举 ans[i]是每次前面有a[i]个可用的答案 找到这一位的答案后 删除已经使用的编号更新线段树 Accode #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int MaxN = 8e4 + 5; const int inf = 0x3f3f3f3f; int n; int a[MaxN],ans[MaxN]; struct NODE{ int l,r,w; }tree[MaxN]; void build(int k,int ll,int rr){ tree[k].l = ll; tree[k].r = rr; tree[k].w = rr - ll + 1; if(ll == rr){ return ; } int m = (ll + rr) / 2; build(2 * k,ll,m); build(2 * k + 1,m + 1,rr); } int ask_p(int k,int x){ if(tree[k].l == tree[k].r){ return tree[k].l

分块入门

北城以北 提交于 2019-12-11 12:11:12
分块就是乱搞(确信 啥是分块 分块本质就是优雅的暴力,通过预处理和根号平衡(玄学地)让复杂度降低 比如我们考虑一个 线段树裸 题: 区间加,区间查询, \(n<=1e5\) 显然暴力的做法是 \(n^2\) 的,那么我们有没有什么优化方法呢? 我们可以将整个序列分为若干块,提前预处理出每个块的和,每次修改如果包含一个整块就直接打标记,非整块范围就暴力修改 时间复杂度 假设我们将 \(k\) 个元素分成一块,那么将一共分出 \(\frac{n}{k}\) 个块 对于修改和查询操作:整块 \(O(1)\) 标记或查询,散块暴力修改,那么一次操作复杂度最高为 \(O(\frac{n}{k}+k)\) 根据均值不等式,当 \(\frac{n}{k}=k\) 时, \(\frac{n}{k}+k\) 最小,也就是说当 \(k=\sqrt{n}\) 时总复杂度最低为 \(O(n\sqrt{n})\) 虽然相比 \(n^2\) 很优秀,但是为啥我不写线段树呢??? 相比其他数据结构优势 众所周知,线段树维护的信息需要能够区间快速合并,但是分块由于过于暴力,可以忽略这个条件 如这道例题: 区间加,区间小于 \(k\) 的个数 线段树已经去世,但是分块仍然可以胜任: 预先将每个块内数字排序,对于修改操作,显然不会影响整块的有序性,对于散块我们可以暴力重构,复杂度 \(O(\sqrt{n}logn)\

【日记】12.10

匆匆过客 提交于 2019-12-11 01:34:33
12.10日记 主席树 P2617(带修主席树模板):给定n个数的序列,查询区间第k小+单点修改。本题非强制在线。 思路 :其实主席树也只是一种复用重复空间的思想,并不是一种特定的数据结构。相反,他和动态开点有不少相似之处。甚至说,普通的线段树就是一种特殊的抽象化线段树。我感觉做了这么多线段树的题目,这是我能总结出来的最好的版本了。 首先是线段树的结构体化: struct Tree{ int l,r,val; Tree(int a=0,int b=0,int c=0):l(a),r(b),val(c){} }v[M*200]; \(l\) 表示左儿子的下标, \(r\) 表示右儿子的下标, \(val\) 表示线段树每个节点的权值。 真正的线段树正是如此。只不过传统上来讲,为了方便初学者理解,大家都是从 \(l=id*2,r=id*2+1\) 这种最简单的线段树开始讲起。实际上左儿子和右儿子并不一定得是固定的二倍关系,甚至都不一定得是两个儿子,你写三个儿子,变成l,m,r,然后操作的时候多搞一下,可能会更优(我口胡的),只不过写起来比较麻烦,而且最多就是差了个常数。 那么如果父亲和儿子不是固定关系的话,那么该怎么确定儿子的下标呢?很简单,就是 动态开点。每次走到一个节点,要去进行操作之前(operate/query),首先先判断一下这个节点是否存在(是否等于0),如果为0

Codeforces Round #406 (Div. 2)

狂风中的少年 提交于 2019-12-09 23:19:14
https://codeforces.com/contest/787/ D - Legacy 题意:有一个n(<=1e5)个节点的图,有q组边,t是目的地。每组边有3种type之一: t1:u v w (u到v有w的单向边) t2:u l r w (u到[l,r]有w的单向边) t3:v l r w ([l,r]到v有w的单向边) 求从第i个节点到t的最短路。 题解: 失败的想法:新增一个节点管理所有的[l,r],这样避免不了对边的遍历。使用链表删除节点来加速对t2区间的操作,但是对t3的无能为力,而且这个t2也很好卡,每次只有dijkstra真正vis的时候才能删除,所以还是n^2的算法。 正解:先把所有的边反向,目的地t变成起始点s。对连续区间的操作,考虑用线段树来优化,假如只是用线段树求两点之间的距离的最小值,空间会存不下,边也会太多。真正的做法是按线段树来给节点分组,叶节点表示原图这个节点本身,内部节点表示其之下的所有叶节点,每个内部节点向其儿子连w为0的有向边。t2的操作使得u连上log(r-l+1)个内部节点,t3的操作使得log(r-l+1)连上v。然后对这4n个点跑一次dijkstra找到对每个节点的最短路。这个算法的优化在于把[l,r]条边分解为log(r-l+1)条,然后根据线段树的结构重用了大量权为0的边,是对失败的想法的正确实现

第五周训练 | 二叉树+线段树

北城以北 提交于 2019-12-08 09:43:30
A - Binary Tree Traversals 记一个模板 #include<iostream> using namespace std; typedef struct Tree{ Tree *left; Tree *right; int value; }Tree; Tree *root; Tree* create(int *preorder,int *inorder,int n) { Tree *temp; for(int i=0;i<n;i++) { if(preorder[0]==inorder[i]) { temp=(Tree*)malloc(sizeof(Tree)); temp->value=inorder[i]; temp->left=create(preorder+1,inorder,i); temp->right=create(preorder+i+1,inorder+i+1,n-i-1); return temp; } } return NULL; } void postOrder(Tree *postTree) { if(postTree!=NULL) { postOrder(postTree->left); postOrder(postTree->right); if(postTree==root) printf("%d\n",postTree-

二维线段树模板题

自古美人都是妖i 提交于 2019-12-07 16:17:19
题目链接: 题意: 给出一个n*n的矩阵,给出矩阵中所有位置的值 给出m个询问 对于每个询问有x,y,l,分表表示坐标与以该坐标为中心的正方形 对于每组查询我们输出该正方形中的最大值跟最小值的和除2向下取整,再用这个值取代原来在(x,y)的值 solve: 明显是二维线段树模板题 ,分别维护x跟y就行了,对于每个点建一棵线段树 #include <bits/stdc++.h> using namespace std; #define ll long long #define re register void read(int &a) { a=0;int d=1;char ch; while(ch=getchar(),ch>'9'||ch<'0') if(ch=='-') d=-1; a=ch^48; while(ch=getchar(),ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+(ch^48); a*=d; } int minn[3205][3205],maxx[3205][3205]; int n,minnn,maxxx; void pushupx1(int l,int r,int nowx,int nowy) { minn[nowx][nowy]=min(minn[nowx<<1][nowy],minn[nowx<<1|1][nowy]); maxx

【12.6】日记

雨燕双飞 提交于 2019-12-07 12:52:28
12.6日记 线段树 HDU1540:单点修改+单点所在最长连续区间 思路 :昨天用了set(平衡树)做的,发现简单的一批,还是学了一下线段树的做法。不过学完了之后发现,确实用线段树还是很有必要的,如果是区间修改的话,平衡树就挂了,就只能用线段树来处理了。更何况还有可能有区间所在最长连续区间之类的题目。 构造 :每个节点存放4个值,lm记录当前区间,以左端点为左端点的最长1区间的长度,rm记录当前区间,以右端点为右端点的最长1区间的长度,mm记录当前区间最长1区间的长度,col是辅助数组,如果当前区间全都是1,那么col=1,如果当前区间全都是0,那么col=0,否则col=-1。显然col可以直接用mm来代替,所以简单写的话存放3个值就可以。 pushup :(核心操作) lm:如果左儿子全为1,则lm[id]=lm[id*2]+lm[id*2+1](因为会扩展到右区间),否则lm[id]=lm[id*2] rm:如果右儿子全为1,则rm[id]=rm[id*2]+rm[id*2+1](因为会扩展到右区间),否则rm[id]=rm[id*2+1] mm:三个值的最大值:mm[id]=max(mm[id*2],mm[id*2+1],rm[id*2]+lm[id*2+1]) col:用mm的值去推。如果mm=0则col=0,如果mm=r-l+1则col=1,否则col=-1。

线段树相关知识点

偶尔善良 提交于 2019-12-06 21:03:26
线段树实现功能: 区间查找和更新 时间复杂度: 更新:O(logn)查找:O(logn) 线段树内存需要开四倍大小,切记!!! 为什么需要开到四倍? https://www.cnblogs.com/FengZeng666/p/11446827.html 理论上是2n-1的空间,但是你递归建立的时候当前节点为r,那么左右孩子分别是2*r,2*r+1,此时编译器并不知道递归已结束,因为你的结束条件是在递归之前的,所以编译器会认为下标访问出错,也就是空间开小了,应该再开大2倍。有时候可能你发现开2,3倍的空间也可以AC,那只是因为测试数据并没有那么大。 来源: https://www.cnblogs.com/OFSHK/p/11997668.html

P5331 [SNOI2019]通信 [线段树优化建图+最小费用最大流]

谁都会走 提交于 2019-12-06 15:08:32
这题真让人自闭…我EK费用流已经死了?… ( 去掉define int long long就过了 ) 我建的边害死我的 spfa 还是spfa已经死了? 按费用流的套路来 首先呢 把点 \(i\) 拆成两个点 \(i\) 和 \(i'\) 令 \(i'\) = \(i+n\) 对任意的 \(i\) 点 建 \(s -> i' -> t\) 表示这个连到控制中心… \(s -> i -> j ->t\) 表示连到某个哨站…流量为 \(1\) 费用为 | \(a_i -a_j\) | 其中 \(s -> i'\) 的流量为 \(1\) 费用为 \(0\) \(i'->t\) 的流量为 \(1\) 费用为 \(W\) 如果直接暴力建图 复杂度是 \(O(n^2)\) 的 边数也是 \(n^2\) 的 显然过不去啊…然后可以考虑权值线段树 离散化完的值最多有 \(n\) 种 然后就按照离散值搞个权值线段树优化建边 按顺序加进去 一定能满足 \(i<j\) 这个要求 所以像主席树一样 一个个加进去就可以了 线段树的具体做法是 对于每个点开两颗线段树(动态开点 \(p\) 向 \(ls_p,rs_p\) 建边……(这个大概就是线段树优化建边的trick… 但是要注意 \(ls_p,rs_p\) 非 \(0\) 否则会多一堆没啥用的边… 至于 \(p -> ls_p\) 那么流量为 \(inf\

计划做题清单

混江龙づ霸主 提交于 2019-12-06 15:02:06
洛谷 并查集P3367 递归P1255 动态规划P1164 排序P1138 优先队列P1323 栈P1449 搜索P1219 八皇后 贪心P1223 P1803 线段树与树状数组 P3368 【模板】树状数组2 P3374 【模板】树状数组1 P3372 【模板】线段树1 P3373【模板】线段树2 OPenJudge 二分 网线切割 枚举 鸡兔同笼 与7无关的数 高精度 \(2^N\) 复习 高精度 读入优化 来源: https://www.cnblogs.com/liuziwen0224/p/11991527.html