差分

70 阅读3分钟

区间操作常见方法:

前缀和: 如果需要不断计算区间的和,则考虑用前缀和

差分: 如果需要对一个区间进行多次修改和查询的问题,则考虑差分

一维差分

对于一维数组进行操作,例题: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()