# D

# 题目大意

这是一道我蠢的没边的题目
给定 (a1,,an),(b1,,bn),(c1,,cn)(a_1, \ldots, a_n), \quad (b_1, \ldots, b_n), \quad (c_1, \ldots, c_n),求

max1x<y<n(i=1xai+i=x+1ybi+i=y+1nci)\max_{1 \le x < y < n} (\sum\limits_{i = 1}^{x} a_i + \sum\limits_{i = x + 1}^{y} b_i + \sum\limits_{i = y + 1}^{n} c_i)

# 数据范围

  • 1n3×1051 \le n \le 3 \times 10^5

# 题解

显然,所求的式子等价于 # preA[x] + preB[y] - preB[x] + preC[n] - preC[y] ,变型有 preA[x] - preB[x] + preB[y] - preC[y] + preC[n]
那么我们不就可以枚举 xx,然后求 maxx+1y<npreBypreCy\max\limits_{x + 1 \le y < n} preB_y - preC_y
这个时候,蠢得没边的我,写出了线段树

python
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
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]
# 再去获得 max_{i = x + 1 -> i = n - 1} sub2[i]

res = max(res, sub1[x] + segTree.query(x + 1, n - 1, 1, 0, segTree.n - 1))

print(res + preC[n])

不能说唐完了,只能说没救了


显然,我们可以维护 sufMax ,去求

maxx+1y<npreBypreCy\max\limits_{x + 1 \le y < n} preB_y - preC_y

需要注意的是,y[x+1,n)y \in [x + 1, n),所以,我们不能从 nn 开始维护 sufMaxsufMax,得从 n1n - 1 开始

python
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
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])

# E

# 题目大意

nn 个人有 nn 个水桶(水桶编号 1n1 \to n),初始时水桶均为空,有一个数组 A=(a1,,an)A = (a_1, \ldots, a_n),代表第 ii 个人会把水桶给 aia_i
现在,进行 10910^9 次操作,每次操作,ii 号人会给手中所有水桶添加 ii 的水,添加后给 aia_i 号人

qq 个询问,每次询问,问 xx 号水桶,在 yy 次操作后,有多少水

# 数据范围

  • 2n2×1052 \le n \le 2 \times 10^5
  • 1q2×1051 \le q \le 2 \times 10^5

# 题解

ii 个桶,第一次操作后,会在 aia_i 手上,第二次操作后会在 aaia_{a_i} 手上 \ldots
倍增

  • fi,jf_{i,j} 表示水桶 ii2j2^j 次操作后,会在谁的手上
  • sumi,jsum_{i,j} 表示水桶 ii2j2^j 次操作后,有多少水
    转移方程为
    f[i, j] = f[f[i][j - 1], j - 1]
    ii 号桶传 2j12^{j - 1} 步到了 fi,j1f_{i, j - 1},再传 2j12^{j-1} 步,到了 f_

sum[i, j] = sum[i, j - 1] + sum[f[i][j - 1], j - 1]
ii 号桶,在传 2j12^{j-1} 步后的水,加上第 ii 号桶传 2j12^{j-1} 步后到的位置(fi,j1f_{i, j-1})再传 2j12^{j-1} 步后的水

初始化

  1. 水桶 ii20=12^0 = 1 次操作后,在 aia_i 手上,fi,0=aif_{i, 0} = a_i
  2. 水桶 ii20=12^0 = 1 次后,有 ii 的水,sumi,0=isum_{i, 0} = i

python
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
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())) # b 号 传 t 次

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)

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

duoxichangan 微信支付

微信支付

duoxichangan 支付宝

支付宝