线段树和树状数组的学习

线段树和树状数组的学习

树状数组

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

实现代码:

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



}
相关推荐
一隅论数智2 天前
给AI一张“业务概念地图“:本体如何从哲学走向企业智能
大数据·人工智能·经验分享·笔记·学习·学习方法·政务
倒头就睡的小比特2 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
XiHongShi20162 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
爱吃苹果的日记本2 天前
离散数学第六课
学习·离散数学
猎头南楼2 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
AI职业加油站2 天前
AI智能体应用工程师证书:政策红利下的职业新风口
大数据·运维·人工智能·学习·职场发展
旖旎夜光2 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark2 天前
大规模并行计算中的负载均衡算法研究4
算法