线段树和树状数组的学习

线段树和树状数组的学习

树状数组

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

实现代码:

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();
    }



}
相关推荐
青山木15 小时前
Hot 100 ---腐烂的橘子
java·数据结构·后端·算法·leetcode·广度优先
未来之窗软件服务15 小时前
计算机考试-快速排序—东方仙盟
数据结构·算法·排序算法·仙盟创梦ide·东方仙盟
小龙报16 小时前
【优选算法】1. 水果成蓝 2.找到字符串中所有字母的异位词
java·c语言·数据结构·数据库·c++·redis·算法
正经人_x16 小时前
学习日记42
学习
一只小菜鸡..16 小时前
南京大学 操作系统 (JYY) 学习笔记:导论与历史的轮回 (OS Introduction)
笔记·学习
小弥儿16 小时前
GitHub 今日热榜 | 2026-07-24:金融 K 线基础模型上榜
学习·金融·开源·github
txzrxz16 小时前
数论:排列数、组合数、费马小定理、逆元、同余定理
c++·算法·数论·组合数·费马小定理·逆元·排列数
xqqxqxxq16 小时前
LeetCode Hot100 双指针专项题解笔记
笔记·算法·leetcode
520拼好饭被践踏16 小时前
JAVA+Agent学习day22
java·开发语言·后端·学习
懿路向前17 小时前
【HarmonyOS学习笔记】2026-07-24 | textProcessing 实体识别与踩坑实录
笔记·学习·边缘计算·harmonyos