java,线段树
线段树:
你可以理解成:线段组成的树,很多人问我,线段树到底有何用处,其实这个问题,你可以自己去刷题,然后总结出检验。
线段的具体理解,我看到一篇很好的博客,我就不展开了。博客地址:https://blog.csdn.net/iwts_24/article/details/81484561
基础题目:
如果我们没有学过线段树,我们肯定是用模拟+暴力的方法。
模拟+暴力的方法代码:
package Combat.com; import java.math.BigInteger; import java.util.Scanner; public class Main { static final int MAX = 50005; static int camp[] = new int[MAX]; public static void main(String []args) { Scanner cin = new Scanner(System.in); int T = cin.nextInt(); for(int i = 1; i <= T; i++) { int N = cin.nextInt(); for(int j = 1; j <= N; j++) { camp[j] = cin.nextInt(); } System.out.println("Case " + i +":" ); search(N); } } static void search(int N) { Scanner cin = new Scanner(System.in); while(true) { String input = cin.next(); if(input.equals("End")) { return; } int i = cin.nextInt(); int j = cin.nextInt(); if(input.equals("Add")) { camp[i] += j; } else if(input.equals("Sub")) { camp[i] -= j; } else { int output = 0; for(int k = i; k <= j; k++) { output += camp[k]; } System.out.println(output); } } } }
上面的代码随着输入的用例越多,是极易超时的。
正确的方法是:线段树中的:单点修改+区间查询。
代码实现如下:
package Combat.com; import java.util.Scanner; public class Main { static final int MAX = 50005; static int camp[] = new int[MAX*4]; static Scanner cin = new Scanner(System.in); public static void main(String []args) { int T = cin.nextInt(); for(int i = 1; i <= T; i++) { int N = cin.nextInt(); buildBinaryTree(1,N,1); System.out.println("Case " + i + ":"); search(N); } } static void search(int N) { while(true) { String input = cin.next(); if(input.equals("End")) { return; } int i = cin.nextInt(); int j = cin.nextInt(); if(input.equals("Add")) { update(1,i,j,1,N); } else if(input.equals("Sub")) { update(1,i,-j,1,N); } else { System.out.println(query(1,i,j,1,N)); } } } static int query(int node,int l,int r,int L,int R)//不用分开考虑是否跨区间。下面的代码已经考虑在内了。 { if(l <= L && R <= r) { return camp[node]; } int mid = (L+R)/2; int sum = 0; if(l <= mid) { sum += query(node*2,l,r,L,mid); } if(r > mid) { sum += query(node*2+1,l,r,mid+1,R); } return sum; } static void update(int node,int pos,int num,int L,int R) { if(L == R) { camp[node] += num; return; } int mid = (L+R)/2; if(pos <= mid) { update(node*2,pos,num,L,mid); } else { update(node*2+1,pos,num,mid+1,R); } camp[node] = camp[node*2]+camp[node*2+1];//这句话极其重要 } static void buildBinaryTree(int L,int R,int node) { if(L == R) { camp[node] = cin.nextInt(); return; } int mid = (L+R)/2; buildBinaryTree(L,mid,node*2); buildBinaryTree(mid+1,R,node*2+1); camp[node] = camp[node*2]+camp[node*2+1]; } }
也是一道单点修改+区间查询。,我出错:主要是数组开得太大了,显示:Memory Limit Exceeded。即是超内存
代码实现实现如下:
import java.util.Scanner; public class Main { static final int MAX = 200005; static int result[] = new int[MAX*4]; static Scanner cin = new Scanner(System.in); public static void main(String []args) { while(cin.hasNext()) { int N = cin.nextInt(); int M = cin.nextInt(); buildBinaryTree(1,N,1); search(N,M); } } static void search(int N,int M) { for(int i = 1; i <= M; i++) { String input = cin.next(); int a = cin.nextInt(); int b = cin.nextInt(); if(input.equals("U")) { update(a,b,1,N,1); } else { System.out.println(query(a,b,1,N,1)); } } } static int query(int l,int r,int L,int R,int node) { if(l <= L && R <= r) { return result[node]; } int mid = (L+R)/2; int Max = 0; if(l <= mid) { Max = Math.max(Max,query(l,r,L,mid,node*2)); } if(mid < r) { Max = Math.max(Max,query(l,r,mid+1,R,node*2+1)); } return Max; } static void update(int pos,int num,int L,int R,int node) { if(L == R) { result[node] = num; return; } int mid = (L+R)/2; if(pos <= mid) { update(pos,num,L,mid,node*2); } else { update(pos,num,mid+1,R,node*2+1); } result[node] = Math.max(result[node*2], result[node*2+1]); } static void buildBinaryTree(int L,int R,int node) { if(L == R) { result[node] = cin.nextInt(); return; } int mid = (L+R)/2; buildBinaryTree(L,mid,node*2); buildBinaryTree(mid+1,R,node*2+1); result[node] = Math.max(result[node*2], result[node*2+1]); } }