树状数组和线段树模板

树状数组:支持单点修改,和前缀求和。

1264.动态求连续区间和

给定 nn 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列[a,b]的连续和。

输入格式

第一行包含两个整数 n 和 m,分别表示数的个数和操作次数。

第二行包含 n 个整数,表示完整数列。

接下来 m 行,每行包含三个整数 k,a,bk,a,b (k=0,表示求子数列[a,b][a,b]的和;k=1,表示第 a 个数加 b)。

数列从 11 开始计数。

输出格式

输出若干行数字,表示 k=0k=0 时,对应的子数列 [a,b][a,b] 的连续和。

数据范围

1≤n≤1000001≤n≤100000,
1≤m≤1000001≤m≤100000,
1≤a≤b≤n

输入样例:

10 5
1 2 3 4 5 6 7 8 9 10
1 1 5
0 1 3
0 4 8
1 7 5
0 4 8

输出样例:

11
30
35

树状数组和线段树模板题:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.Stack;

public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static Scanner sc = new Scanner(System.in);
	static final int N = (int)1e5 + 100;
	static int[] a = new int[N], tr = new int[N];
	static int n;
	private static int lowbit(int x) {
		return x & (-x);
	}
	
	private static void add(int x, int y) {
		for(int i = x; i <= n; i += lowbit(i)) {
			tr[i] += y;
		}
	}
	
	private static int query(int x) {
		int res = 0;
		for(int i = x; i > 0; i -= lowbit(i)) {
			res += tr[i];
		}
		return res;
	}
	public static void main(String[] args) {
		n = sc.nextInt();
		int m = sc.nextInt();
		for(int i = 1; i <= n; i++)a[i] = sc.nextInt();
		for(int i = 1; i <= n; i++)add(i,a[i]);
		
		for(int i = 1; i <= m; i++) {
			int ch = sc.nextInt(), a = sc.nextInt(), b = sc.nextInt();
			if(ch == 1) {
				add(a,b);
			}else {
				int res = query(b) - query(a - 1);
				System.out.println(res);
			}
		}
	}
}

线段树:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Scanner;
import java.util.Stack;



public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static Scanner sc = new Scanner(System.in);
	static final int  N = 100100;
	static int[] w = new int[N];
	static Node[] tr = new Node[4 * N];
	public static void main(String[] args) throws IOException {
		String[] input = bf.readLine().split(" ");
		int n = Integer.parseInt(input[0]);
		int m = Integer.parseInt(input[1]);
		
		String[] str = bf.readLine().split(" ");
		for(int i = 1; i <= n; i++) w[i] = Integer.parseInt(str[i - 1]);
		
		build(1,1,n);
		
		while(m-- > 0) {
			String[] s3 = bf.readLine().split(" ");
            int k = Integer.parseInt(s3[0]);
            int x = Integer.parseInt(s3[1]);
            int y = Integer.parseInt(s3[2]);
            
            if(k == 0)System.out.println(query(1,x,y));
            else modify(1, x, y);
		}
	}
	
	public static void pushUp(int u) {
		tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
	}
	
	public static void build(int u, int l, int r) {
		if(l == r)tr[u] = new Node(l,r,w[l]);
		else {
			tr[u] = new Node(l,r,0);
			int mid = l + r >> 1;
			build(u << 1,l,mid); build(u << 1 | 1,mid + 1, r);
			pushUp(u);
		}
	}
	
	public static int query(int u,int l, int r) {
		if(tr[u].l >= l && tr[u].r <= r)return tr[u].sum;
		else {
			int mid = tr[u].l + tr[u].r >> 1;
			int res = 0;
			if(l <= mid)res += query(u << 1,l,r);
			if(r > mid) res += query(u << 1 | 1, l, r);
			return res;
		}
	}
	
	public static void modify(int u, int x, int v) {
		if(tr[u].l == tr[u].r) tr[u].sum += v;
		else {
			int mid = tr[u].l + tr[u].r >> 1;
			if(x <= mid)modify(u << 1, x, v);
			else modify(u << 1 | 1, x, v);
			pushUp(u);
		}
	}
}
class Node{
	int l,r;
	int sum;
	Node(int l, int r,int sum){
		this.l = l;
		this.r = r;
		this.sum = sum;
	}
}

1265.数星星

由题知,求每颗星星左下方向有多少颗星星就是多少级,输入的顺序,按从低到高,从左到右,也就是说,当前星星的左下角有多少星星就有多少星星,后面的输入不会影响。

由于是从低到高输入,所以只要x坐标小于它,就算是它的左下角

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Scanner;
import java.util.Stack;

public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static Scanner sc = new Scanner(System.in);
	static final int N = 32100;
	static int[] tr = new int[N], level = new int[N];
	private static int lowbit(int x) {
		return x & -x;
	}
	private static void add(int x) {
		for(int i = x ; i < N; i += lowbit(i))tr[i] ++;
	}
	private static int query(int x) {
		int res = 0;
		for(int i = x ; i > 0; i -= lowbit(i))res += tr[i];
		return res;
	}
	public static void main(String[] args) {
		int n = sc.nextInt();
		for(int i = 0; i < n; i++) {
			int x;
			x = sc.nextInt() + 1;
			level[query(x)] ++;
			add(x);
			sc.nextInt();
		}
		for(int i = 0; i < n; i++)System.out.println(level[i]);
	}
}

1270.数列区间最大值

利用线段树,将sum改成max即可;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayDeque;
import java.util.Scanner;
import java.util.Stack;



public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static Scanner sc = new Scanner(System.in);
	static final int  N = 100100;
	static int[] w = new int[N];
	static Node[] tr = new Node[4 * N];
	public static void main(String[] args) throws IOException {
		String[] input = bf.readLine().split(" ");
		int n = Integer.parseInt(input[0]);
		int m = Integer.parseInt(input[1]);
		
		String[] str = bf.readLine().split(" ");
		for(int i = 1; i <= n; i++) w[i] = Integer.parseInt(str[i - 1]);
		
		build(1,1,n);
		
		while(m -- > 0) {
			String[] s = bf.readLine().split(" ");
			int x = Integer.parseInt(s[0]);
			int y = Integer.parseInt(s[1]);
			bw.write(query(1,x,y) + "\n");
		}
		bw.close();
	}
	
	public static void pushUp(int u) {
		tr[u].maxv = Math.max(tr[u << 1].maxv, tr[u << 1 | 1].maxv);
	}
	
	public static void build(int u, int l, int r) {
		if(l == r)tr[u] = new Node(l,r,w[l]);
		else {
			tr[u] = new Node(l,r,0);
			int mid = l + r >> 1;
			build(u << 1, l , mid);build(u << 1 | 1, mid + 1, r);
			pushUp(u);
		}
	}
	
	public static int query(int u, int l, int r) {
		if(tr[u].l >= l && tr[u].r <= r) return tr[u].maxv;
		else {
			int mid = tr[u].l + tr[u].r >> 1;
			int maxx = 0;
			if(l <= mid) maxx = query(u << 1,l,r);
			if(r > mid) maxx = Math.max(maxx,query(u << 1 | 1, l, r));
			return maxx;
		}
	}


}
class Node{
	int l,r;
	int maxv;
	Node(int l, int r,int maxv){
		this.l = l;
		this.r = r;
		this.maxv = maxv;
	}
}

1215.小朋友排队

nn 个小朋友站成一排。

现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。

每个小朋友都有一个不高兴的程度。

开始的时候,所有小朋友的不高兴程度都是 00。

如果某个小朋友第一次被要求交换,则他的不高兴程度增加 11,如果第二次要求他交换,则他的不高兴程度增加 22(即不高兴程度为 33),依次类推。当要求某个小朋友第 kk 次交换时,他的不高兴程度增加 kk。

请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。

如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。

输入格式

输入的第一行包含一个整数 nn,表示小朋友的个数。

第二行包含 nn 个整数 H1,H2,…,HnH1,H2,…,Hn,分别表示每个小朋友的身高。

输出格式

输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。

数据范围

1≤n≤1000001≤n≤100000,
0≤Hi≤10000000≤Hi≤1000000

输入样例:

3
3 2 1

输出样例:

9

样例解释

首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。

只要求出当前位置,前面比他高的个数和后面 比他矮的个数,就是当前位置要调换的最少次数。

利用 w[i]存储每个位置的身高,树状数组存储当前身高的人数。即可用区间和求解。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayDeque;
import java.util.Scanner;
import java.util.Stack;



public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static Scanner sc = new Scanner(System.in);
	static final int  N = 1000010;
	static int[] tr = new int[N],w = new int[N], sum = new int[100100];
	
	public static void main(String[] args) throws IOException {
		int n = Integer.parseInt(bf.readLine().trim());
		String[] s = bf.readLine().split(" ");
		//按顺序存储 每个人的身高
		for(int i = 1; i <= n ;i++) {
			w[i] = Integer.parseInt(s[i - 1]);
		}
		
		//树状数组中存 身高的 人数,查看 身高比w[i] 高的人个数,也就是 查看 在i位置前,身高比i位置高的
		for(int i = 1; i <= n ; i++) {
			sum[i] = query(N - 1) - query(w[i]);
			add(w[i],1);
		}
		
		// 清空 数组
		for(int i = 0; i < N; i++)tr[i] = 0;
		// 查看在i位置后,身高比i小的
		for(int i = n; i >= 1; i--) {
			sum[i] += query(w[i] - 1);
			add(w[i],1);
		}
		
		long res = 0;
		for(int i = 1; i <= n; i++) {
			res += (long)sum[i] * (sum[i] + 1) / 2;
		}
		bw.write(res + "\n");
		bw.flush();
		bw.close();
	}
	private static int lowbit(int x) {
		return x & -x;
	}
	private static int query(int x) {
		int res = 0;
		for(int i = x; i > 0; i -= lowbit(i))res += tr[i];
		return res;
	}
	private static void add(int x, int v) {
		for(int i = x; i < N ;i += lowbit(i))tr[i] += v;
	}
}

差分

输入一个长度为n的整数序列。

接下来输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。

请你输出进行完所有操作后的序列。

输入格式

第一行包含两个整数n和m。

第二行包含n个整数,表示整数序列。

接下来m行,每行包含三个整数l,r,c,表示一个操作。

输出格式

共一行,包含n个整数,表示最终序列。

数据范围

1≤n,m≤1000001≤n,m≤100000,
1≤l≤r≤n1≤l≤r≤n,
−1000≤c≤1000−1000≤c≤1000,
−1000≤整数序列中元素的值≤1000−1000≤整数序列中元素的值≤1000

输入样例:

6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1

输出样例:

3 4 5 3 4 2
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	public static void main(String[] args) throws IOException {
		String[] s = bf.readLine().split(" ");
		int n = Integer.parseInt(s[0]);
		int m = Integer.parseInt(s[1]);
		
		int[] a = new int[n + 10];
		int[] b = new int[n + 10];
		String[] s1 = bf.readLine().split(" ");
		for(int i = 1; i <= n; i++) {
			a[i] = Integer.parseInt(s1[i - 1]);
			b[i] = a[i] - a[i - 1];
		}
		
		while(m -- > 0) {
			String[] s2 = bf.readLine().split(" ");
			int l = Integer.parseInt(s2[0]);
			int r = Integer.parseInt(s2[1]);
			int c = Integer.parseInt(s2[2]);
			b[l] += c;
			b[r + 1] -= c;
		}
		for(int i = 1; i <= n; i++) {
			b[i] = b[i] + b[i - 1];
			bw.write(b[i] + " ");
		}
		bw.close();
	}
}

差分矩阵

输入一个n行m列的整数矩阵,再输入q个操作,每个操作包含五个整数x1, y1, x2, y2, c,其中(x1, y1)和(x2, y2)表示一个子矩阵的左上角坐标和右下角坐标。

每个操作都要将选中的子矩阵中的每个元素的值加上c。

请你将进行完所有操作后的矩阵输出。

输入格式

第一行包含整数n,m,q。

接下来n行,每行包含m个整数,表示整数矩阵。

接下来q行,每行包含5个整数x1, y1, x2, y2, c,表示一个操作。

输出格式

共 n 行,每行 m 个整数,表示所有操作进行完毕后的最终矩阵。

数据范围

1≤n,m≤10001≤n,m≤1000,
1≤q≤1000001≤q≤100000,
1≤x1≤x2≤n1≤x1≤x2≤n,
1≤y1≤y2≤m1≤y1≤y2≤m,
−1000≤c≤1000−1000≤c≤1000,
−1000≤矩阵内元素的值≤1000−1000≤矩阵内元素的值≤1000

输入样例:

3 4 3
1 2 2 1
3 2 2 1
1 1 1 1
1 1 2 2 1
1 3 2 3 2
3 1 3 4 1

输出样例:

2 3 4 1
4 3 4 1
2 2 2 2
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	public static void main(String[] args) throws IOException {
		String[] s = bf.readLine().split(" ");
		int n = Integer.parseInt(s[0]);
		int m = Integer.parseInt(s[1]);
		int q = Integer.parseInt(s[2]);
		
		int[][] a = new int[n + 10][m + 10];
		int[][] b = new int[n + 10][m + 10];
		
		for(int i = 1; i <= n; i++) {
		    String[] s1 = bf.readLine().split(" ");
			for(int j = 1; j <= m; j++) {
				a[i][j] = Integer.parseInt(s1[j - 1]);
				b[i][j] = a[i][j] - a[i - 1][j] - a[i][j - 1] + a[i - 1][j - 1];
			}
		}
		
		while(q -- > 0) {
			String[] s2 = bf.readLine().split(" ");
			int x1 = Integer.parseInt(s2[0]);
			int y1 = Integer.parseInt(s2[1]);
			int x2 = Integer.parseInt(s2[2]);
			int y2 = Integer.parseInt(s2[3]);
			int c = Integer.parseInt(s2[4]);
			
			b[x1][y1] += c;
			b[x2 + 1][y2 + 1] += c;
			b[x2 + 1][y1] -= c;
			b[x1][y2 + 1] -= c;
			
		}
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= m; j++) {
				b[i][j] += b[i-1][j] + b[i][j - 1] - b[i - 1][j - 1]; 
				bw.write(b[i][j] + " ");
			}
			bw.write("\n");
		}
		bw.close();
	}
}
发布了127 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/foolishpichao/article/details/105452366
今日推荐