本文最后更新于:January 19, 2022 pm
纸上得来终觉浅,绝知此事要躬行。路漫漫其修远兮,吾将上下而求索!知识是经过历史的巨人沉淀下来的,别总想着自己能够快速学会,多花点时间去看看,也许会发现些不同的东西。你能快速学会的、觉得简单的东西,对于别人来说也是一样的。人外有人,天外有天。当努力到达了一定的程度,幸运自会与你不期而遇。
目录 核心操作 求某一位数的二进制中最后一位1所在位置表示的数。
public static int lowbit (int x) { return x&(-x); }
单点修改,单点查询 单点修改、单点查询用数组就可以实现。
单点修改,区间查询 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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); }public static void update (int x,int k,int n) { while (x<=n){ tree[x]+=k; x+=lowbit(x); } }public static int query (int x) { int ans = 0 ; while (x>0 ){ ans+=tree[x]; x-=lowbit(x); } return ans; }
区间修改,单点查询 区间修改借助差分是思想。代码同上,只是在调用的时候多调用一次。
updata(x,k); updata(y+1 ,-k);
区间修改,区间查询 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 import java.io.*;import java.math.BigInteger;import java.util.Scanner;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); } public static void update (int i,int k,int n) { int x = 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(); update(x,k,n); update(y+1 ,-k,n); 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(); } }
总结 其实个人感觉就只是两类,一类是区间修改、区间查询;然后其他的是一类。除了区间修改、区间查询的代码不同外,其他的都是一样的代码,只是在调用的灵活处理即可。
总的来说,个人感觉实现的思路都一样,都可以理解成单点修改和单点查询(前缀和)两大部分组成。