# 求出区间[x:y]内所有元素的和 defcheck(left,right): ans = 0 x = right # 先使用原方法求出区间[1:right]的区间和 while x > 0: ans += t[x] x -= lowbit(x) # 然后减去区间[1:left]的元素和,即可获得答案 x = left-1 while x > 0: ans -= t[x] x -= lowbit(x) return ans
defadd(x,v): global n,t while x < n: t[x] += v x += lowbit(x)
defcheck(left, right): global t x = right ans = 0 while x > 0: ans += t[x] x -= lowbit(x) x = left - 1 while x > 0: ans -= t[x] x -= lowbit(x) return ans
# 创建原数组和树状数组 # 注意树状数组的序号从1开始 a = [0] + [int(i) for i ininput().split()] n = len(a) t = [0]*n # 初始化树状数组 # 方法和初始化前缀和数组类似,将每一位的元素加到t[]中 for i inrange(1,n): add(i,a[i]) # 查询修改前的区间和 print(check(2,6)) # 修改原数组中某一元素的值(单点修改) index,value = map(int,input().split()) add(index, value) # 查询修改后的区间和(区间查询) print(check(2,6)) # 具体功能(略),按照题目要求编写
deflowbit(x): return x&(-x) defadd(x,v): global x,t while x < n: t[x] += v defcheck(left,right): global n,t x = right while x > 0: ans += t[x] x -= lowbit(x) x = left - 1 while x > 0: ans -= t[x] x -= lowbit(x) return # 初始化原数组和树状数组 a = [0] + [int(i) for i ininput().split()] n = len(a) t = [0]*(n+1) d = [0]*(n+1) # 用树状数组维护差分数组 for i inrange(1,n): d[i] = a[i] - a[i-1] add(i,d[i]) # 区间修改 l,r,v = map(int,input().split()) # 结合差分数组修改的原理在树状数组上进行单点修改 # 修改d[l],d[r+1] add(l,v) add(r+1,-v) # 单点查询 # 查询原数组第三个元素的值 print(check(3))
六、例题
例题一:异或和(蓝桥杯第14届省赛)
问题描述:
给一棵含有 n 个结点的有根树,根结点为 1 ,编号为 i 的点有点权 ai(i∈[1,n])。现在有两种操作,格式如下: 1xy :该操作表示将点 x 的点权改为 y。 2x :该操作表示查询以结点 x 为根的子树内的所有点的点权的异或和。
现有长度为 m 的操作序列,请对于每个第二类操作给出正确的结果。
输入格式:
输入的第一行包含两个正整数 n,m 用一个空格分隔。第二行包含 n 个整数 $a_1, a_2, … ,a_n
,相邻整数之间使用一个空格分隔。接下来 n−1 行,每行包含两个正整数 ui,vi,表示结点 ui 和 vi之间有一条边。接下来 m 行,每行包含一个操作。
# 求 DFS 序,以便建立树状数组 cnt = 0 defdfs(cur,pre): # cur 是当前节点的序号,pre是上一个节点的序号 global cnt cnt += 1 # 记录将当前节点压入栈中的时间戳 seq[cur][0] = cnt for i in tree[cur]: if pre != i: dfs(i,cur) # 记录将当前元素出栈的时间戳,自此以后的时间戳均与以cur为根节点的树无关 seq[cur][1] = cnt
# 树状数组函数三件套 deflowbit(x): return x&(-x)
defmodify(x,v): global n while x <= n: t[x] ^= v # 计算异或和 x += lowbit(x)
defquery(x): global n ans = 0 while x > 0: ans ^= t[x] x -= lowbit(x) return ans
# 接收输入,创建数据结构 n,m = map(int,input().split()) # a[]存储每一个点的权值 a = [0] + [int(i) for i ininput().split()]
# 用邻接表存储树结构 tree = [[] for i inrange(n+1)] for _ inrange(n-1): u,v = map(int,input().split()) # 注意没说方向,是一个无向边 tree[u].append(v) tree[v].append(u)
# 创建一个二维数组seq[][]记录DFS序 # 其中seq[i]是有2个元素的列表,两个元素分别是第i个节点入栈和出栈的时间戳 seq = [[0,0] for i inrange(n+1)] dfs(1,0)
# 为DFS序数组创建树状数组,并用a[]的值初始化 t = [0]*(n+1) for i inrange(1,n+1): modify(seq[i][0], a[i]) for _ inrange(m): instr = [int(i) for i ininput().split()] if instr[0] == 1: # 修改元素,注意到需要在赋值的同时清除原有元素,所以将原值与新值异或,相当于清除原值 modify(seq[instr[1]][0], a[instr[1]]^instr[2]) # 维护a[],确保其始终保存着每一个节点的当前值 a[instr[1]] = instr[2] else: # 输出单点查询结果 print(query(seq[instr[1]][1]) ^ query(seq[instr[1]][0] - 1))
defadd(x,v): global MAX_SIZE while x < MAX_SIZE: t[x] += v x += lowbit(x)
defask(left,right): ans = 0 x = right while x > 0: ans += t[x] x -= lowbit(x) x = left - 1 while x > 0: ans -= t[x] x -= lowbit(x) return ans
# 主程序 n = int(input()) a = [int(i) for i ininput().split()] t = [0]*MAX_SIZE ans = 0 for i inrange(n): ans += ask(a[i]+1,MAX_SIZE-1) add(a[i],1) print(ans)
deflowbit(x): return x&(-x) defadd(tree,x,v): n = len(tree) while x < n: tree[x] += v x += lowbit(x) defask(tree,x): ans = 0 while x > 0: ans += tree[x] x -= lowbit(x) return ans
# 主程序 n = int(input()) a = [0] + [int(i) for i ininput().split()] b = [0] + [int(i) for i ininput().split()] # 创建一个数组存储每一个a[i]的下标i a1 = [0]*(n+1) for i inrange(1,n+1): a1[a[i]] = i # 创建一个数组存储b[i]在a中的下标 b1 = [0]*(n+1) for i inrange(1,n+1): b1[i] = a1[b[i]] # 创建树状数组 t1 = [0]*(n+1) # 计量树状数组 t2 = [0]*(n+1) # 计数树状数组,和求逆序对的思路类似 # 求解过程 ans = 0 for i inrange(1,n+1): add(t1,b1[i],b1[i]) # 记录b数组中下标小于当前元素的元素的和值 add(t2,b1[i],1) # 记录b数组中下标小于当前元素的元素的个数 ans += b1[i]*ask(t2,b1[i]-1) - ask(t1,b1[i]-1) print(ans)