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

线段树(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?'\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\n",query(1,n,1,x)); 
		if(op == 3)scanf("%d%d",&L,&R),printf("%d\n",query2(1,1,n,L,R));
	}
	return 0;
}

  

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

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

结构体的就懒得打了

自己想去

猜你喜欢

转载自www.cnblogs.com/wangyifan124/p/10294427.html