线段树

【线段树】牛客 Practice for KD Tree (二维线段树/树套树)

北慕城南 提交于 2020-02-01 02:13:35
Practice for KD Tree 题意: 一个 \(n*n\) 矩阵 \(A\) ,有 \(m_1\) 个操作:给 \(x_1\;x_2\;y_1\;y_2\;w\) ,对所有 \(A_{ij}\) ( \(i\in[x_1,x_2]\) 且 \(j\in[y_1,y_2]\) )加上 \(w\) ; 有 \(m_2\) 个询问:给 \(x_1\;x_2\;y_1\;y_2\) ,求出 \(A_{ij}\) ( \(i\in[x_1,x_2]\) 且 \(j\in[y_1,y_2]\) )的最大值。 输入: 第 \(1\) 行 \(3\) 个整数 \(n\;m_1\;m_2\) ( \(1≤n≤2000,1≤m_1≤5*10^4,1≤m_2≤5*10^5\) ); 之后 \(m_1\) 行,每行 \(5\) 个整数: \(x_1\;x_2\;y_1\;y_2\;w\) ( \(1≤x_1≤x_2≤n,1≤y_1≤y_2≤n,1≤w≤10^9\) ); 之后 \(m_2\) 行,每行 \(4\) 个整数: \(x_1\;x_2\;y_1\;y_2\) ( \(1≤x_1≤x_2≤n,1≤y_1≤y_2≤n\) ); 输出: 输出m2行,每行一个整数 官方题解: n小,所以可以用 \(O(n^2)\) 计算出矩阵。然后可以用二维线段树求最值。 个人积累:

hdu 6703 权值线段树 or 主席树

别等时光非礼了梦想. 提交于 2020-01-31 19:13:09
  题意: 给出一个1-n的全排列 a 操作1:修改a[pos] 为 a[pos]+1000000 操作2: 问k的所有后继中(包括k) 最小的 且与a[1]-a[r]均不相等的数是多少 n<=1e5 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ///////////////////////////////////// const int N=2e6+10; int maxx[N<<2],position[N]; void up(int pos) { maxx[pos]=max(maxx[pos<<1],maxx[pos<<1|1]); } void build(int l,int r,int pos) { if(l==r){maxx[pos]=position[l];return ;} int m=(l+r)

线段树

陌路散爱 提交于 2020-01-31 13:49:02
线段树 线段树是一种基于分治思想的二叉树结构,用于在区间上进行信息统计,区间修改. 线段树有如下几种性质 1·每个节点代表一个区间 2·唯一的根节点,代表全部区间 3·每个叶子节点代表一个长度为1的区间 对于每个内部节点 非叶节点,左子节点[l,mid] 右子节点[mid + 1,r] 存储方式 使用数组,仿照二叉堆存储,父的左孩子是 x * 2,右孩子是 x * 2 + 1 使用struct结构存储最后一层会产生空余, 所以数组长度必须为 4N,才不会越界 建树 struct SegmentTree{ int sum,mul,add,maxm; }tree[MAX_N << 2]; void build(int root, int l, int r){ tree[root].mul = 1; tree[root].add = 0; if(l == r)tree[root].sum = a[l]; else{ int mid = (l + r) >> 1; build(root * 2, l, mid + 1); build(root << 1 | 1, mid + 1,r); //求区间最大 tree[root].sum = max(tree[root << 1].sum ,tree[root * 2 + 1].sum); //求区间和值 tree[root].sum =

线段树学习笔记

会有一股神秘感。 提交于 2020-01-31 08:36:59
线段树学习笔记 1. 线段树数组一般开 N*4 的大小(2n - 1 + 2n)。 2. 线段树数组的每一个元素要是一个结构体,存储的信息由 l, r 以及一些题目要求的属性。一般来说,题目求什么就要包含什么信息,然后再考虑这些信息是否可以直接从左儿子和右儿子的信息得到,若不能,就再考虑添加其他的信息。 3. 线段树能够处理的操作:区间(或单点)的动态修改,以及查询。 4. 具体操作模板:pushup, pushdown, build, modify, query. 5. 每次修改或查询都从根节点开始。 来源: CSDN 作者: Victayria 链接: https://blog.csdn.net/Victayria/article/details/104105287

Codeforces Round #524 (Div. 2) F

别说谁变了你拦得住时间么 提交于 2020-01-31 07:50:34
题解: 首先这个东西因为强制在线区间查询 所以外面得套线段树了 然后考虑几条线段怎么判定 我们只需要按照右端点排序,然后查询的时候查找最右节点的前缀最大值就可以了 然后怎么合并子区间信息呢 (刚开始我很zz的觉得应该要线段树合并。。) 线段树都保证了区间一样大每个点暴力也就会算log次。。 于是就直接暴力合并就好了 复杂度$nlogn^2$ 然后因为是cf题。。完全不管常数 成功跑了luogu倒数rank1 感觉前面跑那么快应该是有$nlogn$的做法 #updata: 果然是有nlogn的做法 考虑按照x-y的x从大到小排序建立主席树 ,然后维护每个点y的最小值,线段树上维护最小值的最大值就可以了 于是每次二分找到第一个$>=$它的x位置然后主席树区间查询就可以了 代码: #include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for(int i=h;i<=t;i++) #define dep(i,t,h) for(int i=t;i>=h;i--) #define ll long long #define me(x) memset(x,0,sizeof(x)) #define mep(x,y) memcpy(x,y

codeforces 1295E 线段树维护

笑着哭i 提交于 2020-01-31 06:15:17
codeforces 1295E 线段树 题目描述: 题面链接: http://codeforces.com/contest/1295/problem/E 给两个数组p和a,将p数组分割成两部分,然后可以将前部分移动到后部分,反之也可,移动一个数p[i]为对应数的a[i],问最少花费多少使前部分的值都小于后部分。 解题思路 线段树维护最后前部分的数为0到i的花费的最小值,先初始化将所有数都分到后部分,然后再依次维护分割点为p[1]到p[n-1]所对应的花费最小值,详细看代码。 代码 # include <cmath> # include <iostream> # include <cstring> # include <algorithm> using namespace std ; typedef long long ll ; ll n ; ll tr [ 200005 * 4 ] , tag [ 200005 * 4 ] , p [ 200005 ] , a [ 200005 ] ; void pushd ( ll i ) { tr [ i * 2 ] + = tag [ i ] ; tr [ i * 2 + 1 ] + = tag [ i ] ; tag [ i * 2 ] + = tag [ i ] ; tag [ i * 2 + 1 ] + = tag [ i ] ;

洛谷P1908 逆序对(线段树解法)

拟墨画扇 提交于 2020-01-31 02:24:54
题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。 输入格式 第一行,一个数n,表示序列中有n个数。 第二行n个数,表示给定的序列。序列中每个数字不超过 10910^9 1 0 9 输出格式 给定序列中逆序对的数目。 输入输出样例 输入 #1 6 5 4 2 6 3 1 输出 #1 11 思路:和 POJ2352类似,这个题可以先建一棵空树,然后不断查询不断插点。对于逆序对的定义已经很清楚了,在这里应用桶排序的思想,每个叶子节点保存的是这个数的个数。不考虑题目所给的输入值 1e9范围的话,当从输入读到一个数 a[i]时,若求他的逆序数,只需要统计叶子节点 i+1位置到最终位置的区间和(因为是按照输入顺序插入的,读到第 i个时前面 i-1个数已经进入桶了,统计大于 a[i]的数的个数更新 ans即可。因为先建的是空树,所以可以直接统计到最大范围)。区间查询完毕后进行当前点的插入,最终输出 ans。 这是数字元素范围比较小的情况,但题目给的范围是 1e9, n的范围是 1e5,自然想到要进行离散化

【线段树】牛客 k小数查询 (区间线段树套权值线段树)

社会主义新天地 提交于 2020-01-31 01:19:26
K小数查询 题意: 给一个长度为 n 数列 A ,然后m个操作,有如下两种: · 1 l r x,表示对i \(\in\) [l,r],令 \(A_i=min(A_i,x)\) · 2 l r k,表示询问区间[l,r]中第 k 小的数。 输入描述: 第一行输入两个整数 \(n,m(1≤n,m≤8×10^4)\) 。 接下来一行 n 个整数描述数组 \(A(1≤A_i≤n)\) 。 接下来 m 行每行描述一个操作,操作格式与题面中相同,保证 \(1≤l≤r≤n,1≤k≤r−l+1,1≤x≤10^9\) 输出描述: 对于每组询问,输出一个整数表示答案。 官方题解: 考虑区间线段树套权值线段树求区间k小值的算法:对 \([1,n]\) 建线段树,每一个线段树节点 \([l,r]\) ,用一棵动态开点的权值线段树记录 \([l,r]\) 中每种权值出现了多少次。 如果能够维护这样的数据结构,询问就可以转化为在 \(O(logn)\) 棵权值线段树上二分,能在 \(O(lon^2n)\) 的时间里得到答案。 修改时,首先和普通的区间线段树一样,定位到某些节点[l,r]:这次修改相当于把内层线段树中所有大于等于 \(x\) 的数并到 \(x\) 的位置,这可以被转化成 \(t+1\) 次线段树单点修改操作,其中 \(t\) 为被并入的节点个数。把这 \(t+1\) 次修改应用到内层线段树 \

线段树染色问题(例题为poj2777)

南笙酒味 提交于 2020-01-30 00:06:26
染色问题加离散化是poj2528,过后我会放出来的 关于离散的详细解释参考博客: https://blog.csdn.net/iwts_24/article/details/81603603 区域染色覆盖问题 假设某大学有一面文化墙,各个学院都可以在上面涂色,要求涂色区域高必须和墙一样,宽度任意但必须是整数(以米为单位)。涂色可以覆盖其他学院的涂色。现在若干个学院涂色之后最终这面墙上能看见多少种颜色。 这就是简单的染色问题了。当然有很多种不同的说法,但整体上离不开这两个问题:1.区域覆盖。2.多种染色方式。既然是区域操作,那么用线段树是比较合理了。用数组也可以,但是数据规模稍微大一点就会TLE。 当然,跟染色问题一同存在的还有就是离散化,很多博客也是将这两者一起来写的,并且主要是离散化。但我个人感觉染色问题对理解线段树很有帮助(当然还是太菜了= =大佬们都认为难点是线段树的离散化),所以就单独拿出来了。 建树 线段树有多种表现形式,感觉很多人都是拿结构体写的,博主是用数组写的,其本质还是一样的代码有些不一样而已。 整体上,我们对一段数据建成线段树,那么区域染色的时候就类似与修改区间。而线段树的精髓就是利用lazy数组,可以保证不遍历到子结点就可以获得区域的情况。那么染色也要利用这个性质,对于一段区间,我们想要在上层结点上来表示出来。那么我们可以设置3个变量:-1

zkw线段树

一世执手 提交于 2020-01-29 21:09:16
zkw线段树是zkw大神搞的自底向上线段树,以常数小,代码短著称。然而zkw大神的原ppt中描述简单,想了好长时间才想粗来。 以下内容针对 区间最小值 ,使用更好理解的递归方式描述。 定义 zkw线段树定义如下: 1. 它是一棵 满二叉树 2. 他的叶节点是一个数 3. 每一个非叶节点是一个数,且这个数是它的两个孩子中的较小值 显然,zkw线段树和普通线段树类似。他的叶节点从左到右是一个数列A1..n,非叶节点存一些信息以便查询区间最小值。 由于它是一个满二叉树,可以用 堆式储存法 储存。特别的,由于叶节点的个数为2的正整数幂,对于数据规模n,叶子节点的实际个数为 2 lg n + 1 , 没有数据的节点用 ∞ 填充 。 性质 不难发现,一棵有tn个节点的满二叉树有tn-1个非叶子节点。所以在堆式结构中,第i个叶子节点的位置是 tree[tn-1+i] 。这是一个很重要的性质,zkw线段树的许多操作是建立在他的基础上的。 由1容易得出,对于树上(堆中)任意一个位置i,如果i是偶数,那么它是一个左孩子;否则是一个右孩子。 1 2 3 4 5 6 7 //显然,所有奇数都是右孩子,偶数都是左孩子 建立数据结构 直接用静态数组建立即可,i的左右孩子分别为 i*2,i*2+1 const int maxn = 100000; // 最多节点数 int tree[maxn*4]; //