区间操作常见方法:
前缀和: 如果需要不断计算区间的和,则考虑用前缀和
差分: 如果需要对一个区间进行多次修改和查询的问题,则考虑差分
一维差分
对于一维数组进行操作,例题:www.lanqiao.cn/problems/21…
重新排序
问题描述
给定一个数组 A和一些查询 Li,Ri
求数组中第 Li 至第 Ri个元素之和。
小蓝觉得这个问题很无聊, 于是他想重新排列一下数组, 使得最终每个查 询结果的和尽可能地大。小蓝想知道相比原数组, 所有查询结果的总和最多可 以增加多少?
输入格式
输入第一行包含一个整数 n 。
第二行包含 n 个整数 A1,A2,⋯,An, 相邻两个整数之间用一个空格分隔。
第三行包含一个整数 m 表示查询的数目。
接下来 m 行, 每行包含两个整数 Li、Ri, 相邻两个整数之间用一个空格分隔。
输出格式
输出一行包含一个整数表示答案。
样例输入
5
1 2 3 4 5
2
1 3
2 5
样例输出
4
样例说明
原来的和为 6+14=20, 重新排列为 (1,4,5,2,3) 后和为 10+14=24 增加了 4。
我的代码
# 初始化
N = 100003
d = [0]*N
ans = [0]*N
a = [0]*N
sum1 = 0
sum2 = 0
# 输入
n = int(input())
a = [0] +[ int(i) for i in input().split() ]
m = int(input())
# 给差分数据赋值(将原本的区间赋值从m*n,降为n)
for i in range(m):
l,r = map(int,input().split())
d[l] += 1
d[r+1] -= 1
# 通过差分数组求原来的数组
ans[0]=d[0]
for i in range(1,n+1):
ans[i]=ans[i-1]+d[i]
# 求原始数组的sum
for i in range(1,n+1):
sum1 += ans[i]*a[i]
# 重新排序
ans[1:n+1] = sorted(ans[1:n+1])
a[1:n+1] = sorted(a[1:n+1])
# 求新数组的大小
for i in range(1,n+1):
sum2 += ans[i]*a[i]
print(sum2-sum1)
二维差分
问题描述
小蓝拥有 n×n 大小的棋盘,一开始棋盘上全都是白子。小蓝进行了 m 次操作,每次操作会将棋盘上某个范围内的所有棋子的颜色取反(也就是白色棋子变为黑色,黑色棋子变为白色)。请输出所有操作做完后棋盘上每个棋子的颜色。
输入格式
输入的第一行包含两个整数 n,m,用一个空格分隔,表示棋盘大小与操作数。
接下来 m 行每行包含四个整数 x1,y1,x2,y2,相邻整数之间使用一个空格分隔,表示将在 x1 至 x2 行和 y1 至 y2 列中的棋子颜色取反。
输出格式
输出 n 行,每行 n 个 0 或 1 表示该位置棋子的颜色。如果是白色则输出 0,否则输出 1。
样例输入
3 3
1 1 2 2
2 2 3 3
1 1 3 3
样例输出
001
010
100
我的代码
n,m = map(int,input().split())
cf = [ [0]*(n+2) for i in range(n+2)]
a = [ [0]*(n+2) for i in range(n+2)]
for i in range(m):
x1,y1,x2,y2 = map(int,input().split())
cf[x1][y1]+=1
cf[x1][y2+1]-=1
cf[x2+1][y1]-=1
cf[x2+1][y2+1]+=1
for i in range(1,n+1):
for j in range(1,n+1):
a[i][j]=cf[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1]
print(a[i][j]&1,end='')
print()