线段树 树状数组 并查集

利用线段树十分方便的处理区间,线段树是一棵完美的二叉树,树上的每一个节点都维护一个区间,根维护的是整个区间,线段树通常用来计算区间内数据的和或者是修改某处的值。
线段树
对区间的操作可以再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操作(类似补码)
树状数组BIT
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;
        //向上进行操作
    }
}

B站很详细的详解 看前分钟就可

并查集

并查集
并查集主要是为了找根节点,按照普通方法找的话,应该是从最深的节点往上递归,看看最终的根节点是哪个。(图已经很清楚了)
上代码

#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;
        //进行初始化
    }
}

快速掌握的链接 评论区已经改正错误

©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页