线段树

经典算法题每日演练——第十二题 线段树

无人久伴 提交于 2020-04-02 21:44:21
这一篇我们来看树状数组的加强版线段树,树状数组能玩的线段树一样可以玩,而且能玩的更好,他们在区间求和,最大,平均 等经典的RMQ问题上有着对数时间的优越表现。 一:线段树 线段树又称"区间树”,在每个节点上保存一个区间,当然区间的划分采用折半的思想,叶子节点只保存一个值,也叫单元节点,所 以最终的构造就是一个平衡的二叉树,拥有CURD的O(lgN)的时间。 从图中我们可以清楚的看到[0-10]被划分成线段的在树中的分布情况,针对区间[0-N],最多有2N个节点,由于是平衡二叉树的形 式也可以像堆那样用数组来玩,不过更加耗费空间,为最多4N个节点,在针对RMQ的问题上,我们常常在每个节点上增加一些sum, max,min等变量来记录求得的累加值,当然你可以理解成动态规划的思想,由于拥有logN的时间,所以在RMQ问题上比数组更加优美。 二:代码 1:在节点中定义一些附加值,方便我们处理RMQ问题。 1 #region 线段树的节点 2 /// <summary> 3 /// 线段树的节点 4 /// </summary> 5 public class Node 6 { 7 /// <summary> 8 /// 区间左端点 9 /// </summary> 10 public int left; 11 12 /// <summary> 13 /// 区间右端点 14 /// <

hdu 1556 线段树

可紊 提交于 2020-03-30 12:08:31
这个题其实有O(n)的算法,不过还是用线段树做了一遍,还写了个自认为不错的pushalldown函数,哈哈。 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 100001; 7 int ans[N]; 8 9 struct Node 10 { 11 int l, r, add; 12 } node[N << 2]; 13 14 void build( int i, int l, int r ) 15 { 16 node[i].l = l, node[i].r = r, node[i].add = 0; 17 if ( l == r ) return ; 18 int lc = i << 1, rc = lc | 1, mid = ( l + r ) >> 1; 19 build( lc, l, mid ); 20 build( rc, mid + 1, r ); 21 } 22 23 void pushdown( int i ) 24 { 25 if ( node[i].add ) 26 { 27 int lc = i << 1, rc = lc | 1; 28 node[lc].add += node[i].add; 29

线段树(hdu 1556)

我的梦境 提交于 2020-03-30 12:08:05
Problem Description: N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗? Input 每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。当N = 0,输入结束。 Output 每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。 抱歉啊 这几天发的全是线段树 (上周培训的这个,,,,下周就换点其他的) 这个题也很简单 只需要用到 mark 缓存 其实这道题 用普通的 区间起点终点更新 也可以 反正每一个节点都要访问的。 还是贴代码吧 #include<iostream> #include<stdio.h> using namespace std; bool flag; struct node { int l,r,mark;//直接用mark 标记这一段被刷了几次就可以了 自己画一个图很好理解的 }data[100001*4]; void built(int l,int r,int i) { data[i].l=l; data[i]

线段树专题

北城余情 提交于 2020-03-30 12:03:51
线段树的风格是跟 NotOnlySuccess 学的 单点更新 :最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来 1、 hdu1166 敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。 中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:"你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书

[kuangbin带你飞]专题七 线段树

拟墨画扇 提交于 2020-03-30 12:01:58
https://vjudge.net/contest/66989 A、 敌兵布阵 单点修改、区间查询、维护区间和 1 //CSDN:https://blog.csdn.net/qq_40889820 2 #include<iostream> 3 #include<sstream> 4 #include<fstream> 5 #include<algorithm> 6 #include<cstring> 7 #include<iomanip> 8 #include<cstdlib> 9 #include<cctype> 10 #include<vector> 11 #include<string> 12 #include<cmath> 13 #include<ctime> 14 #include<stack> 15 #include<queue> 16 #include<map> 17 #include<set> 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 #define random(a,b) (rand()%(b-a+1)+a) 20 #define ll long long 21 #define ull unsigned long long 22 #define e 2.71828182 23 #define Pi acos(-1

HDU2795 线段树

戏子无情 提交于 2020-03-30 12:01:19
Billboard Time Limit: 20000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 13 Accepted Submission(s): 11 Problem Description At the entrance to the university, there is a huge rectangular billboard of size h*w (h is its height and w is its width). The board is the place where all possible announcements are posted: nearest programming competitions, changes in the dining room menu, and other important information. On September 1, the billboard was empty. One by one, the announcements started being put on the billboard. Each announcement is a stripe of paper

POJ 3468 (线段树)

和自甴很熟 提交于 2020-03-30 11:45:21
题目链接: http://poj.org/problem?id=3468 You have N integers, A 1 , A 2 , ... , A N . You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. Input The first line contains two numbers N and Q . 1 ≤ N , Q ≤ 100000. The second line contains N numbers, the initial values of A 1 , A 2 , ... , A N . -1000000000 ≤ A i ≤ 1000000000. Each of the next Q lines represents an operation. "C a b c " means adding c to each of A a , A a +1 , ... , A b . -10000 ≤ c ≤ 10000.

poj2352_树状数组&&线段树

那年仲夏 提交于 2020-03-30 10:35:54
题目链接 两种写法所用到的思维是一样的,都是在输入一个星星位置的时候, 先查询比他的x小的星星,再把它插入到树or数组中。 线段树写法: #include<iostream> #include<algorithm> #include<string.h> using namespace std; #define maxn 32000+10 int sum[maxn<<2],level[maxn]; int n; void update(int l,int r,int rt,int data) { sum[rt]++; if(l==r) return; int mid=(l+r)/2; if(data<=mid) update(l,mid,rt<<1,data); else update(mid+1,r,rt<<1|1,data); } int query(int left,int right,int l,int r,int rt) { if(left==l&&right==r) { return sum[rt]; } int mid=(l+r)/2; if(right<=mid) { return query(left,right,l,mid,rt<<1); } else if(left>mid) return query(left,right,mid+1,r,rt<<1|1);

『线段树合并算法入门』

点点圈 提交于 2020-03-30 10:34:02
<更新提示> <第一次更新> <正文> 线段树合并 对于一类问题中,假如我们有若干棵权值线段树,它们都维护相同的值域区间 \([1,n]\) ,我们希望能够将这些线段树对应区间的关键值进行相加,同时继续维护区间最大值/最小值等信息,这就需要用到线段树合并算法。 一般来说,我们会用如下的方式来实现线段树合并: 我们用两个指针 \(p,q\) 分别从两个线段树的根节点出发,同步地遍历两棵线段树,并且合并相同区间的有关信息 $1. $ 若 \(p,q\) 之一为空,则以非空的那个节点作为合并后的节点 \(2.\) 若 \(p,q\) 均不为空,则递归地合并 \(p,q\) 的左右子节点,左后删除节点 \(q\) ,并自底向上更新关键信息,留下节点 \(p\) 作为合并后的节点。如果已经递归到了叶节点,直接将关键值相加即可。 \(Code:\) inline int merge(int p,int q,int l,int r)//两个指针为p,q,当前节点维护的区间为[l,r] { if ( !p || !q ) return p|q; if ( l == r ) { cnt(p) += cnt(q); return p; } int mid = l+r >> 1; ls(p) = merge( ls(p) , ls(q) , l , mid ); rs(p) = merge( rs(p)

sicily --山海经 线段树实例

喜夏-厌秋 提交于 2020-03-30 09:32:14
1 #include <stdio.h> 2 #include <iostream> 3 using namespace std; 4 const int cmax = 100005; 5 const int minnum = -999999999; 6 int ans , s , x , posx , posy ; 7 struct Tnode 8 { 9 10 int maxs , sum , maxl , maxr ; // maxs为当前区间最大的序列和 , sum为当前区间的和 , maxl为当前区间左端点开始的最大序列和 , maxr 11 //为当前空间右端点结束的最大序列和 12 int posi , posj , posl , posr ; //posi为maxs的左端点 , posj为maxs的右端点 , posl为 maxl的右端点 , posr为maxr的左端点 13 int right , left ;//区间左端点 , 区间右端点 14 }tree[cmax * 4]; 15 int temp , count = 0; 16 //从线段树的子节点往根节点更新信息 17 void PushUP(int p) { 18 tree[p].sum = tree[ 2 * p ].sum + tree[ 2* p + 1].sum; 19 tree[p].maxl