线段树

[洛谷P3373] 线段树板子题

匿名 (未验证) 提交于 2019-12-02 23:43:01
线段树区间修改,区间查询模板题 改了n次才过啊!!! 传送门 #include<bits/stdc++.h> using namespace std; #define MAX 100005 struct Node { int l,r; long long lazyadd,lazymul,val; }node[MAX<<2]; long long d[MAX],p; inline void pushup(int rt) { node[rt].val=(node[rt<<1].val+node[rt<<1|1].val)%p; } inline void construct(int rt,int l,int r) { node[rt].l=l; node[rt].r=r; node[rt].lazyadd=node[rt].val=0; node[rt].lazymul=1; if(l==r) { node[rt].val=d[l]; return; } int mid=(l+r)>>1; construct(rt<<1,l,mid); construct(rt<<1|1,mid+1,r); pushup(rt); } inline void pushdown(int rt) { if(node[rt].lazymul!=1) { node[rt<<1].val=(node[rt<<1

dijkstra之zkw线段树优化

匿名 (未验证) 提交于 2019-12-02 23:32:01
其实特别好理解,我们只要写一个数据结构(线段树)支持一下操作: 1.插入一个数 \(x\) 。 2.查询当前数据结构中最小的数的插入编号。 3.删除插入编号为 \(x\) 的数。 第一眼看成可持久化了 其实就是一个单点修改,区间(全局)查询的线段树。 zkw线段树在普通线段树的基础上进行了优化(卡常神器)。 我们记录每一个点在线段树中叶子节点的编号。这样修改的时候就不用递归下去找了,直接一个while循环pushup上来就完事。 #include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<cctype> #include<vector> #include<stack> #include<queue> using namespace std; #define enter puts("") #define space putchar(' ') #define Mem(a, x) memset(a, x, sizeof(a)) #define In inline typedef long long ll; typedef double db; const int INF = 0x3f3f3f3f; const db

权值线段树学习笔记

╄→尐↘猪︶ㄣ 提交于 2019-12-02 23:23:34
权值线段树学习笔记 参考博文: https://www.cnblogs.com/zmyzmy/p/9529234.html 权值线段树: 权值线段树维护 数的个数 ,数组下标代表整个 值域 ,如果太大可以采用离散化。 定义: struct SegmentTree { int l, r; int s; //节点p的s表示这一段值域中数的个数总和 #define l(x) tree[x].l #define r(x) tree[x].r #define s(x) tree[x].s #define lson (p<<1) #define rson (p<<1|1) }tree[maxn<<2]; 建树: void build(int p, int l, int r) { l(p) = l, r(p) = r; if(l == r) { //初始化 return; } int mid = (l + r) >> 1; build(lson, l, mid); build(rson, mid+1, r); //pushup() } 单点更新: void change(int p, int x) { if(l(p) == r(p)) { //更新数据 return; } int mid = (l(p) + r(p)) >> 1; if(x <= mid) change(lson, x);

主席树再探

匿名 (未验证) 提交于 2019-12-02 23:03:14
(零基础者出门左拐) 最近学了主席树,打了几道模板题。 感觉还行 主席树,在我看来就是线段树的可持化 (一开始以为主席树只是可持久化权值线段树) 。在题目中需要建多颗线段树或权值线段树且,相邻的线段树差别不大(一般就一个点不一样)时就可以用主席树。运用可持久化的思想,我们并不需要重新构建一颗线段树,因为只需要改一个点,所以线段树只需要新多出 \(logn\) 个节点,其他的节点继承前面的线段树就行了(所以一般都要开始建一颗空树)。这样一来,我们建树的时间复杂度和、这一堆线段树的空间复杂度变成了 \(nlogn\) ,真是佩服人类的智慧。 嗯,模板题,求区间第k大,我们找到对应的两颗线段树 \(root[r]\) 和 \(root[l-1]\) 然后在这两颗线段数上同时二分就行了。 #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int N=2e5+100; int num,n,m,a[N],b[N],tot,root[N],w[N*20],ch[N*20][2]; void build(int l,int r,int &now){ now=++num; if(l==r)return; int mid

数据结构(二维)方阵问题总结:ST算法、树状数组、线段树、树套树

匿名 (未验证) 提交于 2019-12-02 22:56:40
当我们把区间问题拓展到二维的方阵问题的时候,很多东西,其实就不会再去求那么难的东西了,二维问题主要考察的是从一维到二维的一个转化和拓展 然后,我们还是以静态方阵->带修方阵的顺序来介绍,至于动态方阵,我们可以参考精准覆盖问题的DLX算法中使用的数据结构,那就是舞蹈链,除此以外,在NOIP2017的day2T3,队列一题我们也可以有着启发 然而动态方阵与我们这些老套的数据结构还是脱轨的,此处就不介绍了(强行解释一波) 先说静态方阵,我们针对静态方阵无非就是查询,查询子矩阵的最值或者求子矩阵的和,对于查询子矩阵的最值来说,我们有二维的ST算法撑腰: https://www.cnblogs.com/aininot260/p/9379833.html 而对于子矩阵和的问题,二维的前缀和也是可以胜任的 考虑带修方阵问题,我们如果是修改点查询矩阵,修改矩阵查询点,修改矩阵查询矩阵,可以直接扔给二维树状数组来做,基本秒杀: https://www.cnblogs.com/aininot260/p/9336527.html 而对于修改区间查询区间最值的问题,我们交给功能强大的二维线段树来做(这里是树套树的形式,比四分树更加契合): https://www.cnblogs.com/aininot260/p/9375048.html 我们在区间问题里面曾经引出了一个带lazy tag的

Java实现线段树

匿名 (未验证) 提交于 2019-12-02 21:35:18
Merger接口:定义对区间如何操作 public interface Merger<E> { E merge(E a, E b); } SegmentTree: public class SegmentTree<E> { private E[] tree; private E[] data; private Merger<E> merger; public SegmentTree(E[] arr, Merger<E> merger) { this.merger = merger; data = (E[]) new Object[arr.length]; for(int i = 0; i < arr.length; i++) { data[i] = arr[i]; } tree = (E[]) new Object[4 * arr.length]; buildSegmentTree(0, 0, data.length - 1); } //在treeIndex的位置创建表示区间[l...r]的线段树 private void buildSegmentTree(int treeIndex, int l, int r) { if(l == r) { tree[treeIndex] = data[l]; return; } int leftTreeIndex = leftChild

[机房测试]10.29

不打扰是莪最后的温柔 提交于 2019-12-02 19:54:25
[机房测试]10.29 真的服了这个出题人 欢迎转载ssw02的博客: https://www.cnblogs.com/ssw02/p/11761641.html 辣鸡 看似T1神仙题,结果却是大暴力。 分为3种情况统计答案,注意要先按照 x 排序。(实际上可以被 hack 掉),但随机数据下有一维偏序是可以过很大数据的。 出题人这么说,即使被 Hack 了也么办法呀 T2 神仙数据结构题目。。。。 线段树启发式合并,你可以认为是 Dsu on tree 套上线段树。 先留一个坑 。 题解是这么说的: 对于每一个节点,用一个线段树,下标为时间,存储这个时间子树中是否加入了小球,这个小球对答案的贡献(如果之前有 这种颜色的小球贡献就是0)。在线段树上二分就能求出这个节点的答案。维护这棵线段树可以用启发式合并的方法。 用启发式合并的方式处理出当前子树中的所有操作,同时构建出线段树。 T3 瞎yy一下,发现1和k+1实际上没有什么直接关联。。。。然后DP即可。。。 来源: https://www.cnblogs.com/ssw02/p/11761641.html

[CF620E]New Year Tree_dfs序_线段树_bitset

别来无恙 提交于 2019-12-02 19:45:28
New Year Tree 题目链接 : http://codeforces.com/problemset/problem/620/E 数据范围 :略。 题解 : 转化成序列问题,发现颜色种数特别少,暴力用数组合并显然会$T$,我们用$bitset$优化合并过程即可。 代码 : #include <bits/stdc++.h> #define setIO(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout) #define N 800010 #define ls p << 1 #define rs p << 1 | 1 using namespace std; char *p1, *p2, buf[100000]; #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ ) int rd() { int x = 0, f = 1; char c = nc(); while (c < 48) { if (c == '-') f = -1; c = nc(); } while (c > 47) { x = (((x << 2) + x) << 1) + (c ^ 48), c

[线段树系列] 线段树合并

a 夏天 提交于 2019-12-02 19:14:17
这一篇来讲讲线段树合并。 前置知识: 动态开点线段树 还是一样先给一道例题: [JOI2012] Building2 题面是日文的,这里给出中文翻译: 有 n个城市,它们组成了一棵树。 第 i 个城市有一座高度为 H i 的建筑。 你需要选择一条尽量长路径,设路径中有 k 个点, 依次分别为 i 1 , i 2 , ⋯ i k − 1 , i k, 使得路径满足 H i 1 < H i 2 < ⋯ < H i k, 这 k个点不一定要连续,求 k的最大值。 概述:求树上LIS( 最长上升子序列 ),不会求LIS也没有关系,这只是一道例题。 先来考虑朴素做法: 取出树上的所有路径,对它们分别求LIS。 可以做,但是复杂度太高,不可行。 我们发散思维,容易想到一种做法: 对于每一个点x,我们发现经过它的一条路径的LIS可以由两部分组成。 以x开头,x左边的部分路径如果是下降的,那右边就要是上升的( 值h )。 以x开头,x左边如果是上升的,右边就要是下降的。 画个图方便理解: 图中蓝色的显然就是过x的LIS 根据上面的想法,我们求出以x开头,往左的LIS=3,往右的LDS( 最长下降子序列 )=2。 以x开头,往左的LDS=1,往右的LIS=2。 我们比较两个结果( 相加-1,要把自己重复算的那一次减去 ),4和2,显然答案就是4。 现在考虑怎么实现这个想法, 刚开始

I Hate It HDU - 1754 线段树之单点值修改和区间最大值查询

荒凉一梦 提交于 2019-12-02 19:02:42
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。 这让很多学生很反感。 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。 Input本题目包含多组测试,请处理到文件结束。 在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。 学生ID编号分别从1编到N。 第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。 接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。 当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。 当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。 Output对于每一次询问操作,在一行里面输出最高成绩。Sample Input 5 6 1 2 3 4 5 Q 1 5 U 3 6 Q 3 4 Q 4 5 U 2 9 Q 1 5 Sample Output 5 6 5 9 Hint Huge input,the C function scanf() will work better than cin思路:根据线段树的算法首先是正常建立树