线段树和树状数组的学习

线段树和树状数组的学习

树状数组

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

实现代码:

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



}
相关推荐
zander2588 小时前
LeetCode 32. 最长有效括号
算法
lvwangshu8 小时前
AC 自动机
算法·字符串
koi77u8 小时前
嵌入式学习————————TCP并发服务器(1)
linux·学习
小淮AI16 小时前
从“刷题”到“追问”:AI课堂正在重塑哪些学习旧习惯?
人工智能·学习
shehuiyuelaiyuehao17 小时前
算法31,前缀和,可被k整除的子数组
数据结构·python·算法
wixzjsh17 小时前
TCP通信与HTTP协议学习笔记:粘包、三次握手、四次挥手与C/S、B/S模型
学习·tcp/ip·http
ZhiMuZhiLing17 小时前
拓客软件学习成本实测方法论:从注册到出第一批名单要多久
学习·流量运营·用户运营
程序员大雄学编程18 小时前
微积分46. 无穷级数四大核心性质:从理论到实践的全方位解析
python·学习·微积分·学习工具
203号居民19 小时前
LeetCode hot 100 — 141. 环形链表2
算法·leetcode·链表
玖玥拾19 小时前
LeetCode 202 快乐数
算法·leetcode