nyoj 树状数组 522Interval 116士兵杀敌(二)

认真记录自己的成长,做人事,听天命。


今天认真学习了树状数组这中数据结构,很美的一种结构,下面简单介绍一下树状数组:具体的介绍百度百科很清楚。


我就说一下我对add(update),lowbit,getSum这三个函数的理解

我们知道树状数组是一种求数组连续和的神结构,究竟神在哪里?

1.树状数组求区间和的时间复杂度是logN

2.修改某个只时,同时也修改了区间和,时间复杂度也是logN


那不禁要问了,怎么保证这么高效的呢?

看图


请认真琢磨Cn所管辖的an的个数及下标

C8管辖8个,C7管辖1个,C6管辖2个,C5管辖1个,C4管辖4个,C3管辖1个,C2管辖2个,C1管辖1个....

8=2^3,7=7*(2^0),6=3*(2^1)...可以看出Cn管辖2^exponent个

/*

*字面意思是最低位1----n+lowbit(x)为n在树状数组上的父节点,n-lowbit(x)为n在树状数组上除了Cn所管辖的an之外的an的和

*位运算很神奇....可以在纸上画一画,模拟一下

*/

int lowbit(int x){

return -x&x;

}

/*

*index代表下标,x代表index下标对应值的增量

*/

void add(int index,int x){

while(index<=n){

arr[index]+=x;

index+=lowbit(index);//找到index的父节点

}

}

int getSum(int m){

int ans=0;

while(m>0){

ans+=arr[m];

m-=lowbit(m);//想一想什么意思....

}

return ans;

}

上面讲了基本的原理,但是是针对对树状数组有一点了解的同学,如果感觉有点搞不懂,建议先看一点树状数组的基础。


树状数组的问题一份分为:插线问点和插点问线

problem 116:插点问线

代码:

//插点问线Sum(a,b)=getSum(b)-<span style="font-family: Arial, Helvetica, sans-serif;">getSum(a-1)</span>
import java.io.BufferedInputStream;
import java.io.PrintStream;
import java.util.Scanner;

public class Main {
	static int n;
	static int[] arr = new int[1000001];

	public static void main(String[] args) throws Exception {
		Scanner in = new Scanner(new BufferedInputStream(System.in));
		PrintStream out = System.out;

		n = in.nextInt();
		int m = in.nextInt(), first, second;
		for (int i = 1; i <= n; i++) {//直接构造树状数组
			add(i, in.nextInt());
		}
		while (m-- != 0) {
			char option = in.next().charAt(0);
			first = in.nextInt();
			second = in.nextInt();
			if (option == 'Q') {
				out.println(getSum(second) - getSum(first - 1));
			} else {
				add(first, second);
			}
		}
		out.close();
		in.close();

	}

	static int getSum(int n) {
		int ans = 0;
		while (n > 0) {
			ans += arr[n];
			n -= lowbit(n);
		}
		return ans;
	}

	static void add(int index, int x) {
		while (index <= n) {
			arr[index] += x;
			index += lowbit(index);
		}
	}

	/**
	 * 找父节点或孩子
	 */
	static int lowbit(int x) {
		return -x & x;
	}
}

problem 522插线问点

代码:

import java.io.BufferedInputStream;
import java.io.PrintStream;
import java.util.Arrays;

public class Main {
	static BufferedInputStream bis = new BufferedInputStream(System.in);
	static int[] arr = new int[200005];//将负的转为正的,整体平移向右100001

	public static void main(String[] args) throws Exception {
		PrintStream out = System.out;
		int nCase, n, m;
		nCase = getInt();
		while (nCase-- != 0) {
			n = getInt();
			m = getInt();
			Arrays.fill(arr, 0);
			while (n-- != 0) {
				add(getInt(), 1);
				add(getInt() + 1, -1);//后面的并没有+1,所以减掉
			}
			while (m-- != 0) {
				out.println(getSum(getInt()));
			}
		}
		out.close();
		bis.close();
	}

	static void add(int index, int x) {
		index += 100001;
		while (index < 200005) {
			arr[index] += x;
			index += lowbit(index);
		}
	}

	static int getSum(int n) {
		n += 100001;
		int ans = 0;
		while (n > 0) {
			ans += arr[n];
			n -= lowbit(n);
		}
		return ans;
	}

	static int lowbit(int n) {
		return -n & n;
	}

	static int getInt() throws Exception {
		int i, temp = 0, mark = 1;
		while ((i = bis.read()) < 45)
			;
		if (i == 45) {
			mark = -1;
			i = bis.read();
		}
		while (i > 47) {
			temp = temp * 10 + i - 48;
			i = bis.read();
		}
		return temp * mark;
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值