线段树

可持久化线段树

久未见 提交于 2020-01-22 21:03:58
每次进行单点修改后,会新增 \(log\ n\) 个新节点,即每次更改的结点数为树的高度 增加的非叶子结点一个儿子是其他版本的节点,另一个儿子是连向新节点 空间复杂度为 \(O(n+m\ log\ n)\) \(code\) : void build(int L,int R,int &cur) { cur=++tree_cnt; if(L==R) { val[cur]=a[L]; return; } int mid=(L+R)>>1; build(L,mid,ls[cur]); build(mid+1,R,rs[cur]); } void modify(int L,int R,int pos,int v,int pre,int &cur) { cur=++tree_cnt; ls[cur]=ls[pre],rs[cur]=rs[pre]; val[cur]=val[pre]; if(L==R) { val[cur]=v; return; } int mid=(L+R)>>1; if(pos<=mid) modify(L,mid,pos,v,ls[pre],ls[cur]); if(pos>mid) modify(mid+1,R,pos,v,rs[pre],rs[cur]); } int query(int L,int R,int pos,int cur) { if(L==R)

线段树

邮差的信 提交于 2020-01-20 22:15:02
文章目录 1. 概念 1.1 定义 1.2 使用场景 1.2.1 时间复杂度 2. 线段树——区间求和及更新 3. 线段树——区间最值 4. 碎碎念 5. 参考资料 1. 概念 1.1 定义 线段树使用一个完全二叉树来存储每个区间(segment) 的数据。线段树所使用的二叉树是用一个数组保存的。 完全二叉树:除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对。参考 https://www.zhihu.com/question/19809666/answer/13029983 对于长度为 n 的线段数组有如下性质: 树的高度 log(n) 节点的个数 2n -1「 (n) 叶子节点 +( n -1 ) 内部节点」 <=> 2 ⌈ L o g 2 n ⌉ + 1 2^{⌈ Log_2^n ⌉ + 1} 2 ⌈ L o g 2 n ​ ⌉ + 1 -1 根据完全二叉树的性质,树高 h = ⌈ L o g 2 n Log_2^n L o g 2 n ​ ⌉ +1 ,节点个数 n = 2 h 2^h 2 h - 1 由此节点个数 2 ⌈ L o g 2 n ⌉ + 1 2^{⌈ Log_2^n ⌉ + 1} 2 ⌈ L o g 2 n ​ ⌉ + 1 -1 => 2 ∗ 2 ⌈ L o g 2 n ⌉ 2*2^{⌈ Log_2^n ⌉} 2 ∗ 2 ⌈ L o g 2 n

CodeForces 620E New Year Tree(线段树的骚操作第二弹)

最后都变了- 提交于 2020-01-20 16:19:20
The New Year holidays are over, but Resha doesn't want to throw away the New Year tree. He invited his best friends Kerim and Gural to help him to redecorate the New Year tree. The New Year tree is an undirected tree with n vertices and root in the vertex 1. You should process the queries of the two types: Change the colours of all vertices in the subtree of the vertex v to the colour c . Find the number of different colours in the subtree of the vertex v . Input The first line contains two integers n ,  m ( 1 ≤  n ,  m  ≤ 4·10 5) — the number of vertices in the tree and the number of the

BZOJ-1012&洛谷P1198最大数maxnumber-【JSOI2008】简单线段树

我与影子孤独终老i 提交于 2020-01-20 12:31:03
Time Limit: 3 Sec Memory Limit: 162 MB 洛谷:时间限制 1.00s 内存限制 125.00MB 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1012 洛谷: https://www.luogu.com.cn/problem/P1198 Description   现在请求你维护一个数列,要求提供以下两种操作:1、 查询操作。语法:Q L 功能:查询当前数列中末尾L 个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。2、 插入操作。语法:A n 功能:将n加 上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取 模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个 数。 Input   第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足D在longint内。接下来 M行,查询操作或者插入操作。 Output   对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。 Sample Input 5 100 A 96 Q 1 A 97 Q 1 Q 2 Sample Output 96 93 96 emmm

线段树+Dfs序【CF620E】New Year Tree

吃可爱长大的小学妹 提交于 2020-01-20 10:20:54
Description 你有一棵以1为根的有根树,有n个点,每个节点初始有一个颜色c[i]。 有两种操作: 1 v c 将以v为根的子树中所有点颜色更改为c 2 v 查询以v为根的子树中的节点有多少种不同的颜色 Input 第一行,两个整数 \(n,m\) ,分别代表有 \(n\) 个节点和 \(m\) 个操作。 第二行,共 \(n\) 个整数,代表每个节点的初始颜色 \(c[i]\) 接下来 \(n-1\) 行,描述一条边。 接下来 \(m\) 行,代表每个操作。 Output 对于每个询问操作,输出一行。 刚开始以为是树剖? 结果发现只需要对每个子树操作。 线段树维护 \(dfs\) 序。 对于颜色呢?发现 \(c[i] \leq 60\) 开$long long $可以压成一个数。 因此我们将颜色压缩即可。 记得开$long long $ 虽然没出第二个样例,但我切了 代码 #include<cstdio> #include<iostream> #include<algorithm> #define int long long #define R register using namespace std; const int gz=4e5+8; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(

CF620E New Year Tree 线段树 dfs序

泪湿孤枕 提交于 2020-01-20 08:44:22
luogu链接 题目大意: 有一个节点有颜色的树 操作1.修改子树的颜色 操作2.查询子树颜色的种类 注意,颜色种类小于60种 只有子树的操作,dfs序当然是最好的选择 dfs序列是什么,懒得讲了,自己搜吧 然后开两个数组,begin_和end_记录节点子树在dfs序数组中的开头和结尾 begin,end居然在cf是关键字,还好不是ccf,要不就死了 区间修改一个数,区间查询,线段树的傻逼操作 OK #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define ls rt<<1 #define rs rt<<1|1 #define ll long long const int max4 = 2e6 + 7; const int inf = 0x3f3f3f3f; int n, m; int w[max4], a[max4], begin_[max4], end_[max4]; struct node { int l, r, size, lazy; ll z; void color(int i) { z = z | (1LL << (i - 1)); } void clear() { z = 0LL; } } e[max4];

dfs序线段树

倾然丶 夕夏残阳落幕 提交于 2020-01-20 07:57:04
dfs序+线段树,啥?如果在一棵树上,需要你修改一些节点和查询一些节点,如果直接dfs搜的话肯定超时,那用线段树?树结构不是区间啊,怎么用?用dfs序将树结构转化为一个区间,就能用线段树进行维护了。 dfs序是指:每个节点在dfs深度优先遍历中的进出栈的时间序列,记录每个点进栈和出栈的时间点,会发现每个点在栈中出现两次 比如下面这个图的dfs序: (转载来的图片,太懒不想画) 那么这样转化后我们就可以在上面进行线段树了。对于进栈时间点,我们记录为left[ u ],出栈时间点为right[ u ] 。对于这个区间,我们将每个节点标记为 1~len(dfs序长度) 以这个为区间1~len建线段树, 然后那棵树就没用了!,没用了! 对于修改一个节点x,就是修改left[x](但你的len是等于n的,或者你如果建的是两个节点都算的,你需要update左右编号),对于查询一个区间,就是查询left[x]~right[x],实际上就是线段树。 但是我在刚理解时候总会受原来那颗树的影响,实际上,可以这样理解,比如在这个dfs序中你要修改树节点1(原本的值都是1) ------------------------------> 附上一个例题 POJ 3321 There is an apple tree outside of kaka's house. Every autumn, a lot

HDU5692 Snacks DFS序 线段树

狂风中的少年 提交于 2020-01-20 06:59:48
去博客园看该题解 题目 HDU5692 Snacks Problem Description 百度科技园内有n个零食机,零食机之间通过n−1条路相互连通。每个零食机都有一个值v,表示为小度熊提供零食的价值。 由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。 为小度熊规划一个路线,使得路线上的价值总和最大。 Input 输入数据第一行是一个整数T(T≤10),表示有T组测试数据。 对于每组数据,包含两个整数n,m(1≤n,m≤100000),表示有n个零食机,m次操作。 接下来n−1行,每行两个整数x和y(0≤x,y<n),表示编号为x的零食机与编号为y的零食机相连。 接下来一行由n个数组成,表示从编号为0到编号为n−1的零食机的初始价值v(|v|<100000)。 接下来m行,有两种操作:0 x y,表示编号为x的零食机的价值变为y;1 x,表示询问从编号为0的零食机出发,必须经过编号为x零食机的路线中,价值总和的最大值。 本题可能栈溢出,辛苦同学们提交语言选择c++,并在代码的第一行加上: `#pragma comment(linker, "/STACK:1024000000,1024000000") ` Output 对于每组数据

bzoj 4034(DFS序+线段树)

丶灬走出姿态 提交于 2020-01-20 06:42:29
这个题多了一个操作难度直线上升,看完题解才会写 有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a 。 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。 按照题意:记录其DFS序,然后进栈是正,出栈为负,利用线段树进行更新 #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> #include <vector> #include <stack> using namespace std; typedef long long LL; const int N = 800005; struct Edge { int v,next; } edge[N<<1]; int head[N],tot,cnt; int val[N]; int in[N],out[N]; LL tree[N<<2],lazy[N<<2],seg[N]; int flag[N<<2]; int io[N]; void addEdge(int u,int v) { edge[tot].v = v,edge[tot].next =

【BZOJ-3306】树 线段树 + DFS序

柔情痞子 提交于 2020-01-20 05:38:57
3306: 树 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 792 Solved: 262 [ Submit ][ Status ][ Discuss ] Description 给定一棵大小为 n 的有根点权树,支持以下操作:   • 换根   • 修改点权  • 查询子树最小值 Input   第一行两个整数 n, Q ,分别表示树的大小和操作数。   接下来n行,每行两个整数f,v,第i+1行的两个数表示点i的父亲和点i的权。保证f < i。如 果f = 0,那么i为根。输入数据保证只有i = 1时,f = 0。   接下来 m 行,为以下格式中的一种:   • V x y表示把点x的权改为y   • E x 表示把有根树的根改为点 x   • Q x 表示查询点 x 的子树最小值 Output   对于每个 Q ,输出子树最小值。 Sample Input 3 7 0 1 1 2 1 3 Q 1 V 1 6 Q 1 V 2 5 Q 1 V 3 4 Q 1 Sample Output 1 2 3 4 HINT   对于 100% 的数据:n, Q ≤ 10^5。 Source Solution 有道很类似的题目,不过是树链修改 那道题去要树链剖分,而这里只需要线段树维护一下DFS序即可