线段树

线段树学习—初级基础操作

孤街醉人 提交于 2019-11-30 05:53:12
//这篇博客是不完整的,现在的知识储备,貌似只能写一些基础的应用的 首先的话,来谈下自己对线段树的认识: 线段树可以解决区间加法的问题,比如说,最大值,最小值,区间和的问题, 但是不可以解决不符合区间加法的问题,比如说众数问题。 在网上看了很多版本的线段树,看到了很多的结构体类型的线段树。个人感觉结构体类型的线段树 很好理解,自己觉得的话,线段树主要运用了二分和分治的思想,求一个区间的最大值, 分为两个区间的最大值进行比较,区间和也是先求部分区间的和在求整体。 然后就是运用了二叉树的优点,使得查找时间为logn级别, 修改的话可以分为单点更新和区间更新。区间更新的话需要用到懒惰标记来降低复杂度。 网上其他博客的代码,感觉很好,但是自己敲一遍还是好的。 建树代码: const int maxn = 100005 ; int a [ maxn ] , t [ maxn << 2 ] ; //a为原来区间,t为线段树 void Pushup ( int k ) { //更新函数,这里是实现最大值 ,同理可以变成,最小值,区间和等 t [ k ] = max ( t [ k << 1 ] , t [ k << 1 | 1 ] ) ; } //递归方式建树 build(1,1,n); void build ( int k , int l , int r ) { //k为当前需要建立的结点

关于线段树和树状数组的一些知识集合

我们两清 提交于 2019-11-30 05:48:05
线段树:用于降低时间复杂度的算法 这是昨天大佬讲的一些算法,我自己整理了一些,顺序有点凌乱,下面还有一些网上大佬们的资料,可以当作消遣看一看。 今天也是努力学习的菜鸡啊QAQ 个人觉得线段树这里还是不难理解的,只是我还不会代码实现(哭辽?) 菜鸡要努力啊!冲鸭! 下面是正文部分: *特点: 有根数:根是确定树中一个点作为根 靠近根的为“父” 远离根的为“子”。 二叉树 只有两个分支的树 分为左分支和右分支 有序的 每个节点可以有不同的含义 (例如:可以代表一个区间的和,最大值,最小值等)可以存在标记(标记下放*不太懂) 若节点为(a,b) 左节点(a,(a+b)/2) 右节点((a+b)/2+1,b) 线段树主要处理区间上的问题 每层最多有两个终止节点(*) 标号的概念:即存储每个节点数据的数组下标 *3.标记下放 EX:求Ai-Aj 的和 其中每个点都加n (标记在节点中存储) 树状数组 重要代码实现;(c++) Using namespace std; Void xg(int x) { While(x<=n); { A[x]++; X+=x&(-x);(x累加x的lowbit) } } (以上是自我笔记) 网上资料: 给定区间【L,R】,如何分解成上述给定的区间? 对于给定区间[2,12]要如何分解成上述区间呢? 分解方法一:自下而上合并——利于理解 先考虑树的最下层

线段树入门理解

穿精又带淫゛_ 提交于 2019-11-30 05:46:51
在复习算法至分治法时,书本上主要介绍了合并排序和快速排序,较为简单。特拓展简单学习一个应用了分治法的算法结构——线段树。 acm刷题时遇到许多连续区间的动态查询问题,例如求取某一区间上元素之和、求取某一区间上元素的最大值,此时如果使用一般的方法求解会使得时间超出要求。此时需要使用到线段树,其主要用于高效解决连续区间的动态查询问题。 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN),从而大大减少耗时。 线段树的基本性质如下:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍。 以1到10的区间举例,构造的线段树如下: 而算法构造基础的线段树主要包括 Build (建树函数)、update(更新函数)和query(查询区间和函数)。 Build函数: void Build(int l, int r, int step) //建树,step代表树节点的编号(以下均是) { tree[step].left = l; //赋值 tree[step].right = r; if(l ==r) //l == r时说明伸展到叶子节点,返回 return; int mid = (l+ r) >> 1; //二分建树

[CSP-S模拟测试]:F(DP+线段树)

主宰稳场 提交于 2019-11-30 05:46:29
题目传送门(内部题49) 输入格式 第一行四个整数$n,q,a,b$。 接下来$n$行每行一个整数$p_i$。 输出格式 一行一个整数表示答案。 样例 样例输入: 10 3 3 7 4 2 8 样例输出: 4 数据范围与提示 对于$30\%$的数据:$n,q\leqslant 2,000$ 对于所有数据: $1\leqslant n,q\leqslant {10}^5$ $1\leqslant p_i\leqslant n$ 题解 首先,我们考虑$30\%$的算法怎么办? 考虑$DP$,定义$dp[i][j]$表示到了第$i$步,一个指针在$p_i$,另一个指针在$j$的最短步数。 那么我们可以里出状态转移方程:   $\alpha.dp[i][j]=dp[i-1][j]+|p_i-p_{i-1}|$(上一次和这一次移动的是一个指针)   $\beta.dp[i][p_{i-1}]=dp[i-1][j]+|p_i-j|$(上一次和这一次移动的不是一个指针) 那么我们接着考虑如何优化。 发现转移$\alpha$其实就是将整个区间都加了$|p_i-p_{i-1}|$,而转移$\beta$我们可以维护$dp[i][j]+j$和$dp[i][j]-j$的最小值即可。 所以考虑线段树优化,即可得到满分。 时间复杂度:$\Theta(n\log n)$。 期望得分:$100$分。 实际得分:

线段树

孤街醉人 提交于 2019-11-30 05:40:38
建树 struct node { int L,R; int w;///区间和 int f; }t[4*n+1]; void build(int k,int L,int R) { t[k].L=L; t[k].R=R; if(L==R) { t[k].w=a[i]; ///叶节点 return ; } int m=(L+R)/2; build(k*2,L,m); build(k*2+1,m+1,R); t[k].w=t[k*2].w+t[k*2+1].w; } 懒标记 void down(int k) { t[k*2].f+=t[k].f; t[k*2+1].f+=t[k].f; t[k*2].w+=t[k].f*(t[k*2],R-t[k*2].L+1); t[k*2+1].w+=t[k].f*(t[k*2+1].R-t[k*2+1].L+1); t[k].f=0; } 单点查询 void ask(int k) { if(t[k].L==t[k].R) { ans=t[k].w; return ; } if(t[k].f) down(k); int m=(t[k].L+t[k].R)/2; if(x<=m) ask(k*2); else ask(k*2+1); } 单点修改,对第k个数加上y void add(int k) { if(t[k].L==t[k].R) { t[k].w

Edu73 F Choose a Square (线段树)

醉酒当歌 提交于 2019-11-30 04:38:50
题意 在平面上有 \(n\) 个点, 已知每个点的 \((x, y)\) 及其权值 \(c\) ,现要求在直线 \(y = x\) 上选择正方形的左下角与右上角,使得正方形(含边界)所覆盖点的权值和 与 边长的差值最大,边长可为0,求最大差值并输出可行方案。 传送门 思路 既然正方形的一条对角线在 \(y = x\) 上,则可以在将点坐标离散化之后枚举右上角的坐标 \(y\) ,求 \([1, y]\) 范围内区间和 - 边长的最大值及其下标。 可以采用线段树维护差值的最大值及其下标。 线段树使用   假设点的权值和为 \(sum\) , 正方形左下角坐标为 \((x, x)\) ,右上角坐标为 \((y, y)\) ,则最终答案计算公式为 $ans = sum - (y-x) = sum + x - y $ 。 将所有点的坐标离散化之后,线段树的叶子结点初值赋值为对应的 \(x\) ,其余则为正常维护区间和的最大值及其下标,query出的最大值即为 \(sum+x\) ,减去所枚举的 \(y\) 即为对应 \(ans\) Code #include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6+10; int n; int hsy[maxn<<1], pn; int

cf-877e Danil and a Part-time Job

安稳与你 提交于 2019-11-30 03:34:57
题意 所有房间成一棵有根树,房间1为根节点,每一次pow操作要求把当前节点在内的,以及他的子树全部反转一遍即1变成0,0变成1。每一次get操作进行求和,算出该节点在内的和他子树所有房间为1的个数即求和。 方法:dfs序建线段树,用模板进行修改一下即可。区间反转问题还是一样,要对该区间操作为奇数才进行反转偶数次操作无效,也就对应了lazy标记该怎么推。先初始化线段树然后每一次如果是有效操作,那么sum变成(区间长度-sum)即翻转一次。针对一颗一般的树,我们如果要进行区间修改,一般都有dfs序进行转化成线段树,即求出每一个节点他的子树的开始编号和结束编号,这样因为每一次我们深度优先就可以保证更新区间是连续的。 #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<map> //#include<regex> #include<cstdio> #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i

Codeforces 1192B 全dfs序 + 线段树

孤人 提交于 2019-11-30 03:26:23
题意:给你一颗树,每次会修改一条边的边权,问修改之后的树的直径是多少? 思路:来源于: https://www.cnblogs.com/TinyWong/p/11260601.html 得到树的全序dfs序之后,我们考虑用线段树维护x - 2 * y + z。维护方法和2017, 2016那道题差不多,对于每个区间维护:x, -y, z, x - 2 * y, -2 * y + z, x - 2 * y + z6个部分的最大值,然后区间合并。 代码: #include <bits/stdc++.h> #define ls (o << 1) #define rs (o << 1 | 1) #define LL long long #define INF 1e18 using namespace std; const int maxn = 100010; int lp[maxn], rp[maxn], mp[maxn * 2], tot; vector<pair<int, long long> > G[maxn]; LL d[maxn]; void add(LL x, LL y, LL z) { G[x].push_back(make_pair(y, z)); G[y].push_back(make_pair(x, z)); } struct edge { int u, v; LL w

kuangbin带你飞----线段树专题一(基础操作,单点,区间更新和查询)

大城市里の小女人 提交于 2019-11-30 01:48:27
A 题意:给出q个询问,单点更新和查询 主要是注意模板的书写 #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<map> #include<string> //#include<regex> #include<cstdio> #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; int read

POJ2528 (离散化+线段树)

送分小仙女□ 提交于 2019-11-30 01:10:41
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 89229 Accepted: 25542 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for placing the posters and introduce the following rules: Every candidate can place exactly one poster on the wall. All posters are of the same height equal to the height of the wall; the width of a poster can be any integer number of bytes (byte is the