线段树基本操作(1)

来源:互联网 发布:linux bind,rw 编辑:程序博客网 时间:2024/06/08 11:02

线段树基本操作(1)

(建树,查询和单点修改)

用途

  • 线段树可以快速的对一段区间进行操作,包括求区间最值,并在对某点修改后再次求区间最值,对一个区间上的所有点进行修改
  • 不需要对区间上的元素进行循环,而是一种类似于二分,分治的思想

方法

  1. 把一段长度为2^k的区间逐次对半分,可以总共分成2^(k+1)-1各节点,变成了一棵二叉树
  2. 对于区间[lt, rt],它的子节点为区间[lt, mid]和区间[mid+1, rt]
  3. 查询时只要要查询的区间的左右边界刚好等于已知区间的边界,就可以返回值了,不需要一搜到底
  4. 对于单点修改,基本上和二分查找差不多(查找时查找的值是该点的下标)
//线段树 #include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>using namespace std;const int MAXN = 10000 + 10;int n;int val[2*MAXN], p[MAXN];void build(int node, int lt, int rt)     //建树 {    if(lt == rt) {val[node] = p[lt]; return ;}    int mid = (lt + rt) >> 1;    build(node*2, lt, mid); build(node*2+1, mid+1, rt);    val[node] = min(val[node*2], val[node*2+1]);    return ;}int query(int node, int lt, int rt, int ll, int rr)   //区间查询 //lt, rt:点node的左右区间  ll, rr:要查的左右区间{    if(lt == ll && rt == rr) return val[node];    int mid = (lt + rt) >> 1;    if(rr <= mid) return query(node*2, lt, mid, ll, rr);    if(ll > mid) return query(node*2+1, mid+1, rt, ll, rr);    int v1 = query(node*2, lt, mid, ll, mid);    int v2 = query(node*2+1, mid+1, rt, mid+1, rr);    return min(v1, v2);} // 使用条件:相邻的区间的信息可以被合并成两个区间的并区间的信息void change(int node, int lt, int rt, int u, int add)  //单点修改 //u要修改的值的下标,add要给修改的值加上的值{    if(lt == rt) {val[node] += add; return ;}    int mid = (lt + rt) >> 1;    if(u <= mid) change(node*2, lt, mid, u, add);    if(u > mid) change(node*2+1, mid+1, rt, u, add);    val[node] = min(val[node*2], val[node*2+1]);   //回溯修改  } int main(){    cin >> n;    for(int i = 1; i <= n; i++)        cin >> p[i];    build(1, 1, n);//  int l, r;//  cin >> l >> r;//  cout << query(1, 1, n, l, r);    int u, d;    cin >> u >> d;    change(1, 1, n, u, d);    cout << query(1, 1, n, 2, 4);    return 0;}
0 0
原创粉丝点击