利用线段树十分方便的处理区间,线段树是一棵完美的二叉树,树上的每一个节点都维护一个区间,根维护的是整个区间,线段树通常用来计算区间内数据的和或者是修改某处的值。

对区间的操作可以再O(logn)的时间内完成。
下面我们通过代码实现线段树的构建,修改,区间求和。
#include <iostream>
#include <cstdio>
//线段树
#define MAX_LEN 1000
//构造线段树
void build_tree(int arr[],int tree[],int node,int start,int end){
//start 数组的start
//end 数组的end
//node是根节点
if(start == end){
tree[node] = arr[start];
//如果到下面了然后就把tree赋值了
}
else{
int mid=(start+end)/2;
//分一半
int left_node = 2 * node + 1;
//左边的坐标
int right_node = 2 *node + 2;
//右边的坐标
build_tree(arr,tree,left_node,start,mid);
//往下面造树
build_tree(arr,tree,right_node,mid+1,end);
tree[node]=tree[left_node]+tree[right_node];
//节点等于左右相加和
}
}
void update_tree(int arr[],int tree[],int node,int start,int end,int idx,int val){
if(start == end){
arr[idx] = val;
//到最底下那个要找的点的时候
//就给那个点赋值
tree[node] = val;
}else{
int mid = (start + end) / 2;
int left_node = 2 * node + 1;
int right_node = 2 * node + 2;
if(idx >= start && idx <= mid){
//往左右分散开来
update_tree(arr,tree,left_node,start,mid,idx,val);
} else{
update_tree(arr,tree,right_node,mid+1,end,idx,val);
}
//更新节点(通过搜索到了相应的部位)
tree[node] = tree[left_node] + tree[right_node];
}
}
int query_tree(int arr[],int tree[],int node,int start,int end,int L,int R) {
if(R<start || L>end){
return 0;
//不在计算范围之内
}else if(start == end){
return tree[node];
//到了最下面
}else if(L<=start && R>=end ){
return tree[node];
//在区间内就直接用 不用进行多余的运算
}
int mid = (start+end) / 2;
int left_node = 2 * node + 1;
int right_node = 2 * node + 2;
int sum_left = query_tree(arr,tree,left_node,start,mid,L,R);
int sum_right = query_tree(arr,tree,right_node,mid+1,end,L,R);
return sum_left+sum_right;
}
int main() {
int arr[]={1,3,5,7,9,11};
int size=6;
int tree[MAX_LEN]={0};
build_tree(arr,tree,0,0,size-1);
return 0;
}
最为重要的就是lowbit操作(类似补码)

1 + lowbit(1)=2;
2 + lowbit(2)=4;
4 + lowbit(4)=4;
3 + lowbit(3)=4;
这样在给数组的某一个值向上添加的时候就可以逐层向上操作了
代码实现
int bit[MAX_N+1],n;
int sum(int i){
int s = 0;
while(i>0){
s+=bit[i];
i -=(i&-i);
}
return s;
}
void add(int i,int x){
while (i<=n){
bit[i] += x;
i+=i&-i;
//向上进行操作
}
}
并查集

并查集主要是为了找根节点,按照普通方法找的话,应该是从最深的节点往上递归,看看最终的根节点是哪个。(图已经很清楚了)
上代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
int fa[maxn];
int fi(int x){
return fa[x]==x?x:fa[x]==fi(fa[x]);
//如果自己是根节点返回自己
//反正返回自己的上一级节点
}
void union1(int x,int y){
int p1=fi(x);
//做这个就相当于把x连接到根节点上了
int p2=fi(y);
//同理
//如果x等于y那么就退出
if(x==y)return;
fa[x]=y;
}
int check(int x,int y){
int p1=fi(x),p2=fi(y);
if(p1==p2)return 1;
//如果根节点一样就返回1喽
else return 0;
}
int main(){
for(int i=0li<maxn;i++){
fa[i]=i;
//进行初始化
}
}
本文深入探讨了线段树的构建、修改及区间求和操作,并介绍了并查集的基本原理与应用,提供了丰富的代码实例,帮助读者快速掌握这两种数据结构。

523

被折叠的 条评论
为什么被折叠?



