苍天阻我寻你,此情坚贞如一
给定两个长度为nnn的数组a,ba, ba,b,满足−103≤ai,bi≤103-10 ^ 3 \leq a_i, b_i \leq 10 ^ 3−103≤ai,bi≤103,每个数字xxx表示向前走xxx步,如果是负数则后退嘛,设小AAA执行aaa数组,小BBB执行bbb数组。
有三种操作:
- 把aaa数组中下标为xxx的数修改为yyy。
- 把bbb数组中下标为xxx的数修改为yyy。
- 如果小AAA起始位置在xxx,小BBB起始位置在yyy,问如果他们各自按照数组a,ba, ba,b执行,在第几步能够行动轨迹重合。
如何判定行动轨迹重合:
假设小AAA走过的区间为[l1,r1][l1, r1][l1,r1],小BBB走过的区间为[l2,r2][l2, r2][l2,r2],如果重合则有max(l1,l2)≤min(r1,r2)max(l1, l2) \leq min(r1, r2)max(l1,l2)≤min(r1,r2),
接下来如何确定小AAA和小BBB走过的区间,设aaa数组的前缀和数组为sum_asum\_asum_a,bbb数组的前缀和数组为sum_bsum\_bsum_b,
数组sum_asum\_asum_a的前缀最小,前缀最大值数组为min_a,max_amin\_a, max\_amin_a,max_a,数组sum_bsum\_bsum_b的前缀最小,前缀最大值数组为min_b,max_bmin\_b, max\_bmin_b,max_b,
由小AAA,小BBB的初始位置x,yx, yx,y,可以确定l1=min(x,x+min_a,r1=max(x,x+max_a),l2=min(y,y+min_b,r2=max(y,y+max_b)l1 = min(x, x + min\_a, r1 = max(x, x + max\_a), l2 = min(y, y + min\_b, r2 = max(y, y + max\_b)l1=min(x,x+min_a,r1=max(x,x+max_a),l2=min(y,y+min_b,r2=max(y,y+max_b)。
所以有一个较为暴力的算法 二分 + 线段树 去checkcheckcheck答案,当时这样操作复杂度是O(nlog2n)O(n \log ^ 2 n)O(nlog2n)的,对于n=106n = 10 ^ 6n=106的数据显然是不可行的。
考虑线段树上二分:
假设当前答案在区间为[l,r][l, r][l,r],如果答案在[mid+1,r][mid + 1, r][mid+1,r]上,一定有[1,mid][1, mid][1,mid]这段区间的前缀最大,前缀最小得到的两个区间是不相交的,
另开四个变量来记录区间[1,l−1][1, l - 1][1,l−1]中AAA的前缀最小, 最大,BBB的前缀最小,最大,
用这四个变量跟区间[l,mid][l, mid][l,mid]的最大最小来判断,答案是否落在[l,mid][l, mid][l,mid]之间,直到递归到叶节点,进行判断是否符合条件即可。
#include <bits/stdc++.h>
#define mid (l + r >> 1)
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define ls rt << 1
#define rs rt << 1 | 1using namespace std;typedef pair<int, int> pii;const int N = 1e6 + 10;int a[N], b[N], sum[N], n, m;struct Seg_tree {int maxn[N << 2], minn[N << 2], lazy[N << 2];void push_up(int rt) {minn[rt] = min(minn[ls], minn[rs]);maxn[rt] = max(maxn[ls], maxn[rs]);}void push_down(int rt) {if (!lazy[rt]) {return ;}lazy[ls] += lazy[rt], lazy[rs] += lazy[rt];minn[ls] += lazy[rt], minn[rs] += lazy[rt];maxn[ls] += lazy[rt], maxn[rs] += lazy[rt];lazy[rt] = 0;}void build(int rt, int l, int r) {if (l == r) {maxn[rt] = minn[rt] = sum[l];return ;}build(lson);build(rson);push_up(rt);}void update(int rt, int l, int r, int L, int R, int v) {if (l >= L && r <= R) {lazy[rt] += v;minn[rt] += v, maxn[rt] += v;return ;}push_down(rt);if (L <= mid) {update(lson, L, R, v);}if (R > mid) {update(rson, L, R, v);}push_up(rt);}pii query(int rt, int l, int r, int L, int R) {if (l >= L && r <= R) {return {minn[rt], maxn[rt]};}push_down(rt);pii ans = {0x3f3f3f3f, -0x3f3f3f3f};if (L <= mid) {pii res = query(lson, L, R);ans.first = min(ans.first, res.first);ans.second = max(ans.second, res.second);}if (R > mid) {pii res = query(rson, L, R);ans.first = min(ans.first, res.first);ans.second = max(ans.second, res.second);}return ans;}
}A, B;bool judge(int l1, int r1, int l2, int r2, int x, int y) {l1 = min(x, x + l1), r1 = max(x, x + r1);l2 = min(y, y + l2), r2 = max(y, y + r2);int L = max(l1, l2), R = min(r1, r2);return L <= R;
}int query(int rt, int l, int r, int min_a, int max_a, int min_b, int max_b, int x, int y) {if (l == r) {int cur_mina = min(min_a, A.minn[rt]), cur_maxa = max(max_a, A.maxn[rt]);int cur_minb = min(min_b, B.minn[rt]), cur_maxb = max(max_b, B.maxn[rt]);if (judge(cur_mina, cur_maxa, cur_minb, cur_maxb, x, y)) {return l;}return -1;}A.push_down(rt), B.push_down(rt);int cur_mina = min(min_a, A.minn[ls]), cur_maxa = max(max_a, A.maxn[ls]);int cur_minb = min(min_b, B.minn[ls]), cur_maxb = max(max_b, B.maxn[ls]);if (judge(cur_mina, cur_maxa, cur_minb, cur_maxb, x, y)) {return query(lson, min_a, max_a, min_b, max_b, x, y);}else {return query(rson, cur_mina, cur_maxa, cur_minb, cur_maxb, x, y);}
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);scanf("%d %d", &n, &m);for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);sum[i] = sum[i - 1] + a[i];}A.build(1, 1, n);for (int i = 1; i <= n; i++) {scanf("%d", &b[i]);sum[i] = sum[i - 1] + b[i];}B.build(1, 1, n);for (int i = 1, op, x, y; i <= m; i++) {scanf("%d %d %d", &op, &x, &y);if (op == 1) {A.update(1, 1, n, x, n, -a[x]);a[x] = y;A.update(1, 1, n, x, n, a[x]);}else if (op == 2) {B.update(1, 1, n, x, n, -b[x]);b[x] = y;B.update(1, 1, n, x, n, b[x]);}else {if (x == y) {puts("0");continue;}printf("%d\n", query(1, 1, n, 0x3f3f3f3f, 0, 0x3f3f3f3f, 0, x, y));}}return 0;
}