线段树

【模板】树套树

生来就可爱ヽ(ⅴ<●) 提交于 2019-11-28 06:05:53
在这里先给出一道模板题 【XSY2685】【LG3380】【BZOJ3196】【TYVJ1730】二逼平衡树 \(Description\) 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名(一个数的排名是小于这个数的个数+1) 2.查询区间内排名为 \(k\) 的值 3.修改某一位值上的数值 4.查询 \(k\) 在区间内的前驱(前驱定义为小于 \(x\) ,且最大的数) 5.查询 \(k\) 在区间内的后继(后继定义为大于 \(x\) ,且最小的数) \(Input\) 第一行两个数 \(n,m\) 表示长度为 \(n\) 的有序序列和 \(m\) 个操作 第二行有 \(n\) 个数,表示有序序列 下面有 \(m\) 行, \(opt\) 表示操作标号 若 \(opt=1\) 则为操作 \(1\) ,之后有三个数 \(l,r,k\) 表示查询 \(k\) 在区间 \([l,r]\) 的排名 若 \(opt=2\) 则为操作 \(2\) ,之后有三个数 \(l,r,k\) 表示查询区间 \([l,r]\) 内排名为 \(k\) 的数 若 \(opt=3\) 则为操作 \(3\) ,之后有两个数 \(pos,k\) 表示将 \(pos\) 位置的数修改为 \(k\) 若 \(opt=4\) 则为操作 \(4\)

【模板】线段树

蓝咒 提交于 2019-11-28 06:05:37
一.最基础的线段树:支持区间加减修改,区间查询。   其实两个差分树状数组也可以搞定这个事情,不过还是线段树这样更加直观一点。   建议初步接触线段树的同学先看主程序再看函数,然后有需要可以手动模拟一下,有助于理解每个函数的作用~ #include<bits/stdc++.h> using namespace std; struct SegTree { int l,r; long long sum,Lazy; }Tree[400040]; int n,m,x,y,z,opt; long long a[100010]; void push_up(int k) { Tree[k].sum=Tree[k<<1].sum+Tree[k<<1|1].sum; } void Build(int k,int l,int r) { Tree[k].l=l; Tree[k].r=r; if(l==r) { Tree[k].sum=a[l]; return; } int mid=l+r>>1; Build(k<<1,l,mid); Build(k<<1|1,mid+1,r); push_up(k); } void push_down(int k) { if(Tree[k].Lazy) { Tree[k<<1].sum+=Tree[k].Lazy*(Tree[k<<1].r-Tree[k<<1].l+1

初级线段树小结

佐手、 提交于 2019-11-28 05:40:38
  线段树是一种高效的维护区间的数据结构, 他是通过树的特点,进行了区间的二分法, 通过不断地分治、递归,完成了区间数据的高效管理与维护!   为了区间的方便书写, 我们常常把线段树的区间取为 2 的幂 , 方便进行区间的二分, 与形成一个 完美二叉树 (与完全二叉树有些许的区别, 完全二叉树可以在最后一层中缺少若干节点。)      线段树常常会有一下几种操作, 包括   1.线段树的初始化;(注意初始化过程当中的规模确定,确定线段树的大小)   2. 修改某个节点的数值;(修改过程中,需要不断地对区间进行维护)   3. 求某段区间的最小值  (这里说的是维护最小值的线段树,当然递归的话, 你也可以维护最大值!)   关于以上三种操作的实现: /* 在此处我们建立的是维护最小值的线段树, 维护的是其他的话吗,仅仅只需要改一些初始化以及更新的细节点 */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <string> #include <cctype> #include <algorithm> #include <vector> #include <queue> #include <list> #include <map>

uoj218_火车管理

断了今生、忘了曾经 提交于 2019-11-28 04:02:39
题意 \(n\) 个位置,每个位置一个栈,三种操作,询问区间栈顶的和,区间入栈某个数,单点出栈某个数。 分析 用一个线段树来维护栈顶的和,区间(单点)更新和区间询问。 用一个主席树来维护每个位置最新一次入栈的时间,即 主席树存的是时间,然后取出的时间也能作为主席树的下标来访问对应时间的版本 。 因此区间入栈的时候区间更新线段树和区间更新主席树。 单点出栈时,先查询这个位置栈顶元素的入栈时间,然后再用这个时间的上一个版本的主席树查询栈顶下一个元素的入栈时间,根据入栈时间可以知道入栈的元素,然后由于栈顶已经出栈,所以新的栈顶就是该元素,单点更新线段树和主席树。 代码 #include <bits/stdc++.h> #define ls i<<1 #define rs i<<1|1 #define mid (l+r)/2 using namespace std; typedef long long ll; const int N=8e5+50; int n,m,ty,o,l1,r1,x[N]; struct ST{ //lz:区间赋值标记 sum:区间和 ll lz[N*4],sum[N*4]; void pushup(int i){ sum[i]=sum[ls]+sum[rs]; } void pushdown(int i,int l,int r){ if(lz[i]){ lz[ls

P3372 线段树

一笑奈何 提交于 2019-11-28 03:46:05
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和 输出格式: 输出包含若干行整数,即为所有操作2的结果。 输入输出样例 输入样例#1: 复制 5 5 1 5 4 2 3 2 2 4 1 2 3 2 2 3 4 1 1 5 1 2 1 4 输出样例#1: 复制 11 8 20 #include<iostream> #include<cstdio> using namespace std; const int maxn = 100005; int n, m,a[maxn*2]; struct tree { int left, right;//左端点,右端点 long long value, tag;//维护的值(这题的区间和)以及懒标志 }t[maxn*4]; void build(int p, int x, int y)//构建树 { t[p].left = x;/

线段树

倖福魔咒の 提交于 2019-11-28 03:11:38
大佬的理解 https://www.cnblogs.com/TheRoadToTheGold/p/6254255.html 含义: 二叉树的变异升级(节点存储黑科技) 运用: 到时候在说(目前不清楚) 变异二叉树的建树代码: struct node { int l,r,黑科技; }tree[M]; void setree(int l,int r,int a) { tree[a].l=l;tree[a].r=r; if(r-l==1) //根节点返回 (我采用的是n至n+1为一个单位长度;) return; int mid=(l+r)/2; setree(l,mid,a*2); //因为是完全二叉树 a*2与a*2+1分别是a的左树根和右树根 setree(mid,r,a*2+1); //mid是否加一 取决于单位长度的定义 } 变异完全二叉树的建立 来源: https://www.cnblogs.com/Lamboofhome/p/11388224.html

BZOJ-2298|区间dp|线段树

泪湿孤枕 提交于 2019-11-28 02:24:30
problem a Description 一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数) Input 第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai、bi Output 一个整数,表示最少有几个人说谎 Sample Input 1 3 2 0 0 2 2 2 Sample Output 1 1 Hint 100%的数据满足: 1≤n≤100000 0≤ai、bi≤n Source BZOJ-2298 思路: https://blog.csdn.net/niiick/article/details/82857386 https://blog.csdn.net/z_mendez/article/details/46991699 dp[i]=max{dp[j-1]+sum[j][i]} j < i 其中sum[x][y] 表示(x~y)名次中有多少人。 dp做法代码已AC #include<bits/stdc++.h> using namespace std; const int maxn = 1e6+10; int n; map<pair<int,int>,int > mp; vector<vector<int> > v; int dp[maxn]; int main(){

划分树

試著忘記壹切 提交于 2019-11-28 01:34:01
划分树,类似线段树,主要用于求解某个区间的第k 大元素(时间复杂度log(n)),快排本也可以快速找出,但快排会改变原序列,所以每求一次都得恢复序列。 什么是划分树?   划分树是一种基于线段树的数据结构,也利用了分治的思想,却比线段树高效很多,这是为什么?因为划分树又多了一个性质:在划分时不是随意划分,也不是排序后直接划分(因为这样会破坏原有结构),而是排序后仍保持原来的相对顺序再分到左右子树。 具体实现方法:   整个过程分为建树和查询两个阶段: 1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 #include<algorithm> 5 using namespace std; 6 7 const int MAXN=100010; 8 int tree[30][MAXN];//表示每层每个位置的值 9 int sorted[MAXN];//已经排序的数 10 int toleft[30][MAXN];//toleft[p][i]表示第i层从1到i有多少个数分入左边 11 12 void build(int l,int r,int dep) 13 { 14 if(l==r)return; 15 int mid=(l+r)>>1; 16 int same=mid-l+1;/

线段树

别来无恙 提交于 2019-11-28 01:33:26
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 typedef long long ll; 7 int n , m; 8 ll mod; 9 int num[100003]; 10 struct node 11 { 12 ll sum , add , mul; 13 }tree[100003 << 2]; 14 void update(int p) 15 { 16 tree[p].sum = (tree[p << 1].sum + tree[p << 1 | 1].sum) % mod; 17 } 18 void down(int p , int l , int r) 19 { 20 int mid = (l + r) >> 1; 21 tree[p << 1].sum = ( tree[p << 1].sum * tree[p].mul + tree[p].add * (mid - l + 1) ) % mod; 22 tree[p << 1 | 1].sum = ( tree[p << 1 | 1].sum * tree[p].mul + tree[p].add * (r - mid) ) % mod;

jzoj6310-Global warming【线段树,LIS】

风流意气都作罢 提交于 2019-11-28 00:48:02
正题 题目大意 给出一个长度为 n n n 的序列 a a a ,可以选择一个区间 [ l , r ] [l,r] [ l , r ] 使得 a i = a i + d ( l ≤ i ≤ r , ∣ d ∣ ≤ x ) a_i=a_i+d(l\leq i\leq r,|d|\leq x) a i ​ = a i ​ + d ( l ≤ i ≤ r , ∣ d ∣ ≤ x ) 。求最长上升子序列的最大值。 解题思路 我们可以发现肯定有一种最优解法是选择 [ k , n ] [k,n] [ k , n ] 加上 x x x 。因为比较显然,这里不做解释,如果不懂可以在评论说。 然后我们可以求出数组 f i f_i f i ​ 表示以 i i i 结尾的 L I S LIS L I S 长度, g i g_i g i ​ 表示以 i i i 开头的 L I S LIS L I S 长度。这里用线段树 O ( n log ⁡ n ) O(n\log n) O ( n lo g n ) 求即可。 然后我们可以枚举这个 k k k ,然后 a n s = g k + m a x { f i } ( i < k , a i < a k + x ) ans=g_k+max\{f_i\}(i< k,a_i<a_k+x) a n s = g k ​ + m a x { f i ​ } ( i < k