线段树和树状数组的学习

线段树和树状数组的学习

树状数组

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

实现代码:

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



}
相关推荐
辰海Coding2 小时前
MiniSpring框架学习-整合 IoC 和 MVC(NPC)
学习·spring·mvc
全糖可乐气泡水3 小时前
Codex适配国产信创环境安装部署与技术适配全解析
开发语言·git·python·算法·百度
h_a_o777oah3 小时前
状态机+划分型 DP :深度解析K-划分问题下 DP 状态的转移逻辑(洛谷P2679 P2331 附C++代码)
c++·算法·动态规划·acm·状态机dp·划分型dp·滚动数组优化
05候补工程师3 小时前
从算法理想向工程现实的跨越:SLAM 核心架构、思维误区与 Nav2 实战避坑指南
人工智能·算法·安全·架构·机器人
知识分享小能手4 小时前
Flask入门学习教程,从入门到精通,数据库操作 — 知识点详解与案例代码(4)
数据库·学习·flask
手写码匠4 小时前
Android 17 适配实战指南:新特性解读、隐私变更与迁移全攻略
人工智能·深度学习·算法·aigc
珊瑚里的鱼5 小时前
leetcode42雨水
算法·leetcode
wubba lubba dub dub7505 小时前
第四十八周学习周报
学习
水木流年追梦5 小时前
大模型入门-大模型的推理策略
开发语言·python·算法·正则表达式·prompt