• 线段树 建树 单点修改 单点/区间查询


    线段树(sgement tree)是一种分治思想的二叉树结构,用于在区间上进行信息统计。与按照二进制位进行区间划分的树状数组相比,线段树是一种更加通用的结构:

    1. 线段树的每个节点都代表一个区间。
    2. 线段树具有唯一的根节点,代表的区间是整个统计范围,如[1,n]。
    3. 线段树的每个叶节点都代表一个长度为1的元区间,如[x,x]

    线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

    使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

    在这片文章中,我先讲一下最基本的建树,单点修改,单点/区间查询

    线段树是一种用空间换时间的算法开建树的数组时切记 一定要开4倍的数组

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=10000+10;
    int a[maxn],sum[maxn*4];     //四倍空间
    inline int read(){     //快读,没啥特殊意思
    	int s=0,w=1;
    	char ch=getchar();
    	while(ch<='0' || ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){s=s*10+ch-48;ch=getchar();}
    	return s*w;
    }
    inline void pushup(int root){ //这个节点的值是该节点的左节点加右节点的和
    	sum[root] = sum[root<<1]+sum[root<<1|1];
    }//乘2是该节点的左节点,再加1则是右节点
    inline void build(int l,int r,int root){//建树 
    	if(l == r){
    		sum[root] = a[l];
    		return;
    	}
    	int mid = (l+r)>>1;
    	build(l,mid,root<<1);
    	build(mid+1,r,root<<1|1);
    	pushup(root);
    }
    inline void update(int l,int r,int root,int num,int w){//更新 
    	if(l == r){
    		sum[root] += w;
    		return;
    	}
    	int mid = (l+r)>>1;
    	if(num <= mid)update(l,mid,root<<1,num,w);
    	if(num > mid)update(mid+1,r,root<<1|1,num,w);
    	pushup(root);
    }
    inline int query(int l,int r,int root,int num){//查询
    	if(l == r)return sum[root];
    	int mid = (l+r)>>1;
    	if(num <= mid)return query(l,mid,root<<1,num);
    	if(num > mid)return query(mid+1,r,root<<1|1,num);
    }
    inline int query2(int root,int l,int r,int L,int R){//区间查询
        if(L <= l && r <= R)
            return sum[root];
        int mid = (l+r)>>1,tmp = 0;
        if(L <= mid)
            tmp += query2(root<<1,l,mid,L,R);
        if(mid < R)
            tmp += query2(root<<1|1,mid+1,r,L,R);
        return tmp;
    }
    int main(){
    	int n;
    	n = read();
    	for(int i = 1;i <= n;i++)scanf("%d",&a[i]);
    	build(1,n,1);
    //	for(int i = 1;i <= n*2-1;i++)printf("%d%c",sum[i],i == n?'
    ':' ');
    	for(int i = 1,op,x,y,L,R;i <= 10;i++){
    		scanf("%d",&op);
    		if(op == 1)scanf("%d%d",&x,&y),update(1,n,1,x,y);
    		if(op == 2)scanf("%d",&x),printf("%d
    ",query(1,n,1,x)); 
    		if(op == 3)scanf("%d%d",&L,&R),printf("%d
    ",query2(1,1,n,L,R));
    	}
    	return 0;
    }
    

      

    数组实现线段树建树,单点修改,区间/单点查询

    如果单单只是区间查询就没必要pushdowm,用不着

    结构体的就懒得打了

    自己想去

  • 相关阅读:
    人事不干人事,这算什么事
    java 单例模式
    Java 中类的加载顺序
    新的挑战
    读《月亮和六便士》所思
    读《奇特的一生》后的一些感悟
    BTrace
    Java技能树
    Android Intent
    一个ListView优化的例子
  • 原文地址:https://www.cnblogs.com/wangyifan124/p/10294427.html
Copyright © 2020-2023  润新知