线段树和树状数组的学习

线段树和树状数组的学习

树状数组

作用: 单点修改,区间查询

实现代码:

java 复制代码
static class BIT{
    int n ;
    long[] tree;
    BIT(int n){
        this.n = n;
        tree = new long[n+1];  
    }
    
    int lowbit(int i){
        return i & -i;
    }
    
    void add(int i, int v){
        while( i <= n){
            tree[i] += v;
            i += lowbit(i);
        }
    }
    
    long query(int i){
        long ans = 0;
        while( i > 0 ){
            ans += tree[i];
            i -= lowbit(i);
        }
        return ans;
    }
    
}

应用

1) 求逆序对

使用树状数组维护每一个数出现的次数。当数组长度过长时,可以使用离散化进行优化。

java 复制代码
//========不适用离散化    n: 数组长度  ==============
BIT b = new BIT(n);
int[] p = new int[n+1]; // 给定的数组
long ans = 0;
for(int i = 1;i <= n ; i++){
    int smallerOrEqual = b.query(p[i]); // 查询小于或者等于p[i]的数字的个数
    ans += (i-1) - smallerOrEqual; // 到此时,数组共有i个数 , p[i] 前面有 i-1 个数, i-1 - samllerOrEqual 是大于 p[i] 的个数
    b.add(p[i],1);     // 加入树状数组中
}


//==========使用离散化: 利用HashMap 实现 ===========
BIT b = new BIT(n);
//===== 离散化 ======
int[] p = new int[n];
int[] c =p.clone();
Arrays.sort(c); // 对数组进行排序
int idx = 1;
for(int x : c){
    if(!map.containsKey(x)){
        map.put(x,idx++);
    }
}
//===== 使用树状数组统计逆序对=========
long ans = 0 ;
for(int i =0;i<n;i++){
    int rank = map.get(p[i]); // 获取排序
    int smallerOrEqual = b.query(rank); //看看排在rank前面有多个数
    ans += (i-smallerOrEqual);
    b.add(rank,1);
}

线段树

区间修改,区间查询

java 复制代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

// 线段树
public class SegementTree {
    static int MAXN = 100001;
//     线段树数组  最多4倍的节点数
    static long[] sum = new long[MAXN<<2];
//     懒惰标记数组
    static long[] add = new long[MAXN<<2];
    //原始数组
    static int[] arr = new int[MAXN];
    static int n,m;

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;


    public static void main(String[] args) {
        n = nextInt();
        m = nextInt();

        for(int i =1 ;i<=n;i++){
            arr[i] = nextInt();
        }
        build(1,n,1);
        while(m-->0){
            int op = nextInt();
            if(op == 1) {
                int x = nextInt();
                int y = nextInt();
                int k = nextInt();
                add(x,y,k,1,n,1);
            }else{
                int x = nextInt();
                int y = nextInt();
                long ans = query(x,y,1,n,1);
                System.out.println(ans);
            }
        }

    }

    public static void up(int i){
        sum[i] = sum[i<<1] + sum[i<<1|1];
    }
    public static void lazy(int i, long v ,int len){
        add[i] += v;
        sum[i] += v*len;
    }
    public static void down(int i, int ln, int rn){
        if(add[i]!=0){
            lazy(i<<1,add[i],ln);
            lazy(i<<1|1,add[i],rn);
            add[i] = 0;
        }
    }
    public static void add(int jobl, int jobr , long v ,int l ,int r , int i ){
        if(jobl <= l && jobr >= r){
            lazy(i,v ,r-l+1);
        }else{
            int mid = (l + r) >> 1;
            down(i,mid-l+1,r-mid);
            if(jobl <= mid) add(jobl,jobr ,v , l , mid ,i<<1);
            if(jobr > mid) add(jobl,jobr,v,mid+1,r,i<<1|1);
            up(i);
        }
    }
    public static long query(int jobl, int jobr  ,int l ,int r , int i ){
        if(jobl <= l && jobr >= r){
            return sum[i];
        }else{
            int mid = (l + r) >> 1;
            long ans = 0;
            down(i,mid-l+1,r-mid);
            if(jobl <= mid) ans+=query(jobl,jobr , l , mid ,i<<1);
            if(jobr>mid) ans+=query(jobl,jobr,mid+1,r,i<<1|1);
            return ans;
        }
    }
    public static void build(int l ,int r ,int i){
        if(l == r) sum[i] = arr[l];
        else{
            int mid = (l+r) >> 1;
            build(l,mid ,i<<1);
            build(mid+1,r,i<<1|1);
            up(i);
        }
    }
    public static int nextInt(){
        return Integer.parseInt(next());
    }
    public static String next(){
        while (st == null || !st.hasMoreElements()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return st.nextToken();
    }



}
相关推荐
ZhengEnCi8 小时前
GPT-6 Astra 爆改 Qwen 权重真有那么神吗:权重空间编程 0.016% 参数的真相
算法·架构
罗西的思考9 小时前
【轻量化复刻大模型 / KIMI K3】KDA(Kimi Delta Attention):并行
人工智能·算法·机器学习
视觉小萌新9 小时前
AI Class 3 · Chapter 1:变量、字符串、list/dict、if/for(python学习-小白版-有经验可跳过)
python·学习·list
夜不会漫长11 小时前
C++:红黑树
数据结构·算法
AI备案指南-满满12 小时前
算法备案审核不通过,一般是什么原因?
java·人工智能·算法·大模型备案·算法备案·大模型登记
Ramble_Naylor12 小时前
Rust深度解读:Send 与 Sync 的本质与线程安全边界
python·算法·rust
秋天的怀念_David12 小时前
算法一千零一夜 · 第二十三夜 电力民生写成的曲线
java·程序人生·算法
不一样的故事12612 小时前
NB/T 47013.8-2015 附录D 吸枪技术
人工智能·经验分享·算法
通问AI12 小时前
用 200 行 Python 给文档库做「上下文完整度」自检:四个可复算的检查项
算法
揽星河..12 小时前
【C语言】扫雷游戏
c语言·算法·游戏