# 题目大意
这是一道我蠢的没边的题目
给定 (a1,…,an),(b1,…,bn),(c1,…,cn),求
1≤x<y<nmax(i=1∑xai+i=x+1∑ybi+i=y+1∑nci)
# 数据范围
- 1≤n≤3×105
# 题解
显然,所求的式子等价于 # preA[x] + preB[y] - preB[x] + preC[n] - preC[y] ,变型有 preA[x] - preB[x] + preB[y] - preC[y] + preC[n]
那么我们不就可以枚举 x,然后求 x+1≤y<nmaxpreBy−preCy 吗
这个时候,蠢得没边的我,写出了线段树
python1 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
| MAXXX = 10**30
class SegTree: def __init__(self, data): self.n = len(data) self.tree = [0] * (4 * self.n) self.build(data, 1, 0, self.n - 1) def build(self, data, node, l, r): if l == r: self.tree[node] = data[l] else: mid = (l + r) // 2 self.build(data, node * 2, l, mid) self.build(data, node * 2 + 1, mid + 1, r) self.tree[node] = max(self.tree[node * 2], self.tree[node * 2 + 1])
def query(self, ql, qr, node, l, r): if ql > r or qr < l: return -MAXXX if ql <= l and r <= qr: return self.tree[node] mid = (l + r) // 2
return max(self.query(ql, qr, node * 2, l, mid), self.query(ql, qr, node * 2 + 1, mid + 1, r))
n = int(input()) a = [0] + list(map(int, input().split())) b = [0] + list(map(int, input().split())) c = [0] + list(map(int, input().split()))
preA = [0 for _ in range(n + 1)] preB = [0 for _ in range(n + 1)] preC = [0 for _ in range(n + 1)] sub1 = [0 for _ in range(n + 1)] sub2 = [0 for _ in range(n + 1)]
for i in range(1, n + 1): preA[i] = preA[i - 1] + a[i] for i in range(1, n + 1): preB[i] = preB[i - 1] + b[i] sub1[i] = preA[i] - preB[i] for i in range(1, n + 1): preC[i] = preC[i - 1] + c[i] sub2[i] = preB[i] - preC[i]
segTree = SegTree(sub2)
res = -MAXXX
for x in range(1, n - 1): ans = sub1[x]
res = max(res, sub1[x] + segTree.query(x + 1, n - 1, 1, 0, segTree.n - 1))
print(res + preC[n])
|
不能说唐完了,只能说没救了
显然,我们可以维护 sufMax ,去求
x+1≤y<nmaxpreBy−preCy
需要注意的是,y∈[x+1,n),所以,我们不能从 n 开始维护 sufMax,得从 n−1 开始
python1 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
| MAXXX = 10**30
n = int(input()) a = [0] + list(map(int, input().split())) b = [0] + list(map(int, input().split())) c = [0] + list(map(int, input().split()))
preA = [0 for _ in range(n + 1)] preB = [0 for _ in range(n + 1)] preC = [0 for _ in range(n + 1)] sub1 = [0 for _ in range(n + 1)] sub2 = [0 for _ in range(n + 1)] sufMax = [-MAXXX for _ in range(n + 10)]
for i in range(1, n + 1): preA[i] = preA[i - 1] + a[i] for i in range(1, n + 1): preB[i] = preB[i - 1] + b[i] sub1[i] = preA[i] - preB[i] for i in range(1, n + 1): preC[i] = preC[i - 1] + c[i] sub2[i] = preB[i] - preC[i]
for i in range(n - 1, 0, -1): sufMax[i] = max(sufMax[i + 1], sub2[i])
res = -MAXXX
for x in range(1, n - 1): ans = sub1[x] res = max(res, sub1[x] + sufMax[x + 1])
print(res + preC[n])
|
# 题目大意
n 个人有 n 个水桶(水桶编号 1→n),初始时水桶均为空,有一个数组 A=(a1,…,an),代表第 i 个人会把水桶给 ai 人
现在,进行 109 次操作,每次操作,i 号人会给手中所有水桶添加 i 的水,添加后给 ai 号人
有 q 个询问,每次询问,问 x 号水桶,在 y 次操作后,有多少水
# 数据范围
- 2≤n≤2×105
- 1≤q≤2×105
# 题解
第 i 个桶,第一次操作后,会在 ai 手上,第二次操作后会在 aai 手上 …
倍增
- fi,j 表示水桶 i 在 2j 次操作后,会在谁的手上
- sumi,j 表示水桶 i 在 2j 次操作后,有多少水
转移方程为
f[i, j] = f[f[i][j - 1], j - 1]
第 i 号桶传 2j−1 步到了 fi,j−1,再传 2j−1 步,到了 f_
sum[i, j] = sum[i, j - 1] + sum[f[i][j - 1], j - 1]
第 i 号桶,在传 2j−1 步后的水,加上第 i 号桶传 2j−1 步后到的位置(fi,j−1)再传 2j−1 步后的水
初始化
- 水桶 i 在 20=1 次操作后,在 ai 手上,fi,0=ai
- 水桶 i 传 20=1 次后,有 i 的水,sumi,0=i
python1 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
| n, q = list(map(int, input().split())) a = [0] + list(map(int, input().split()))
f = [[0 for j in range(31)] for i in range(n + 10)] sum = [[0 for j in range(31)] for i in range(n + 10)]
for i in range(1, n + 1): f[i][0] = a[i] sum[i][0] = i
for j in range(1, 31): for i in range(1, n + 1): f[i][j] = f[f[i][j - 1]][j - 1] sum[i][j] = sum[i][j - 1] + sum[f[i][j - 1]][j - 1]
for i in range(q): t, b = list(map(int, input().split()))
res = 0
for j in range(30, -1, -1): num = (1 << j)
if num <= t: res += sum[b][j] b = f[b][j] t -= num print(res)
|