蓝桥杯JAVA-12.树状数组模板(JAVA实现)

蓝桥杯复习知识点汇总

目录

核心操作

求某一位数的二进制中最后一位1所在位置表示的数。

public static int lowbit(int x){
    return x&(-x);
}

单点修改,单点查询

单点修改、单点查询用数组就可以实现。

单点修改,区间查询

    public static int maxd = 100000+7;

    public static int[] a = new int[maxd]; //原数组
    public static int[] tree = new int[maxd]; //树状数组

    public static int lowbit(int x){
        return x&(-x);
    }

    //在x位置加上k,n为数组最大值
    public static void update(int x,int k,int n){
        while(x<=n){
            tree[x]+=k;
            x+=lowbit(x);
        }
    }

    //区间查询求1~x的和(即前缀和)
    public static int query(int x){
        int ans = 0;
        while(x>0){
            ans+=tree[x];
            x-=lowbit(x);
        }
        return ans;
    }

区间修改,单点查询

区间修改借助差分是思想。代码同上,只是在调用的时候多调用一次。

//[x,y]区间内加上k
updata(x,k);    //A[x] - A[x-1]增加k
updata(y+1,-k);        //A[y+1] - A[y]减少k

区间修改,区间查询

import java.io.*;
import java.math.BigInteger;
import java.util.Scanner;


/**
 * @Author DragonOne
 * @Date 2021/12/5 21:27
 * @墨水记忆 www.tothefor.com
 */
public class Main {
    public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
    public static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    public static Scanner sc = new Scanner(System.in);

    public static int maxd = 100000+7;

    public static int[] a = new int[maxd]; //原数组
    public static int[] sum1 = new int[maxd];
    public static int[] sum2 = new int[maxd];

    public static int lowbit(int x){
        return x&(-x);
    }

    //在i位置加上k,n为数组最大值
    public static void update(int i,int k,int n){
        int x = i; //后面需要i,所以不能改变i的值
        while(x<=n){
            sum1[x] +=k;
            sum2[x] +=k*(i-1);
            x+=lowbit(x);
        }
    }

    //求前缀和
    public static int query(int i){
        int ans = 0,x=i;
        while(x>0){
            ans+=i*sum1[x]-sum2[x];
            x-=lowbit(x);
        }
        return ans;
    }

    public static void main(String[] args) throws Exception {

        int n = nextInt();
        for(int i=1;i<=n;++i){
            a[i]=nextInt();
            update(i,a[i]-a[i-1],n); //输入初值的时候,也相当于更新了值,差分中也是这样实现的
        }
        int x=nextInt();
        int y = nextInt();
        int k = nextInt();
        //区间[x,y]加上k
        update(x,k,n);
        update(y+1,-k,n);
        //求[x,y]区间和
        int sum = query(y) - query(x-1);


        closeAll();
    }

    public static void cinInit(){
        cin.wordChars('a', 'z');
        cin.wordChars('A', 'Z');
        cin.wordChars(128 + 32, 255);
        cin.whitespaceChars(0, ' ');
        cin.commentChar('/');
        cin.quoteChar('"');
        cin.quoteChar('\'');
        cin.parseNumbers(); //可单独使用来还原数字
    }

    public static int nextInt() throws Exception{
        cin.nextToken();
        return (int) cin.nval;
    }
    public static long nextLong() throws Exception{
        cin.nextToken();
        return (long) cin.nval;
    }
    public static double nextDouble() throws Exception{
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws Exception{
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll() throws Exception {
        cout.close();
        in.close();
        out.close();
    }

}

总结

其实个人感觉就只是两类,一类是区间修改、区间查询;然后其他的是一类。除了区间修改、区间查询的代码不同外,其他的都是一样的代码,只是在调用的灵活处理即可。

总的来说,个人感觉实现的思路都一样,都可以理解成单点修改和单点查询(前缀和)两大部分组成。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值