线段树作为数据结构中可以说是最重要的一个,在2016day2T2中首次在noip中出现虽然正解不是线段树
这就必须要求我们掌握这一数据结构,况且noip也不是我们的终点。
线段树是一种二叉搜索树,和区间树相似,我们将一个区间划分成一些单位区间,每个单位区间又对应着一个叶子节点
线段树可以实现快速查找(logn)修改
线段树是一种平衡二叉树,节点数是n即区间的长度
我们直接看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1001;
int z[N],tree[N << 2]; //z[N]表示一开始输入的数
//这份代码时间复杂度低一些,但是tree的大小必须至少 = 4*N
#define lson l,m,rt<<1 //规定左子树是father << 1
#define rson m+1,r,rt<<1|1 // .............+1
void build(int l,int r,int t);
void update(int rt);
int query(int l,int r,int rt,int nowl,int nowr);
int main(){
cin>>n;
for(int i = 1;i <= n;i++){
cin>>z[i];
}
build(1,n,1);
return 0;
}
//sum表示区间和
void build(int l,int r,int t){
if(l == r){
sum[rt] = z[l] //到了叶子结点显然区间和等于这个数
return;
}
int m = (l + r) >> 1;l//m是分界点,然后我们分别初始化它的左子树和右子树
build(lson);
build(rson);
update(rt); // update是计算sum值的函数,因为题目不同update函数不同为了方便拿出来写
}
void update(int rt){
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
//询问
int guery(int l,int r,int rt,int nowl,int nowr){
if(nowl <= 1 && nowr > r) return sum[rt];
int m = (l + r) >> 1;
int ans = 0;
if(nowl <= m) ans += query(lson,nowl,nowr);
if(m < nowr) ans += query(rson,nowl,nower);
return ans;
}
//单点修改 把第i个位置改成v
void modify(int l,int r,int rt,int p,int v){
if(l == r){
sum[rt] = v;
return; // z找到了这个数
}
int m = (l + r) >> 1;
if(p <= m) modify(lson,p,v);
else modify(rson,p,v);
update(rt);
}