L 苍天阻我寻你,此情坚贞如一(西南科技大学2021届新生赛)(线段树)
蒼天阻我尋你,此情堅(jiān)貞如一
給定兩個(gè)長度為nnn的數(shù)組a,ba, ba,b,滿足?103≤ai,bi≤103-10 ^ 3 \leq a_i, b_i \leq 10 ^ 3?103≤ai?,bi?≤103,每個(gè)數(shù)字xxx表示向前走xxx步,如果是負(fù)數(shù)則后退嘛,設(shè)小AAA執(zhí)行aaa數(shù)組,小BBB執(zhí)行bbb數(shù)組。
有三種操作:
- 把aaa數(shù)組中下標(biāo)為xxx的數(shù)修改為yyy。
- 把bbb數(shù)組中下標(biāo)為xxx的數(shù)修改為yyy。
- 如果小AAA起始位置在xxx,小BBB起始位置在yyy,問如果他們各自按照數(shù)組a,ba, ba,b執(zhí)行,在第幾步能夠行動(dòng)軌跡重合。
如何判定行動(dòng)軌跡重合:
假設(shè)小AAA走過的區(qū)間為[l1,r1][l1, r1][l1,r1],小BBB走過的區(qū)間為[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走過的區(qū)間,設(shè)aaa數(shù)組的前綴和數(shù)組為sum_asum\_asum_a,bbb數(shù)組的前綴和數(shù)組為sum_bsum\_bsum_b,
數(shù)組sum_asum\_asum_a的前綴最小,前綴最大值數(shù)組為min_a,max_amin\_a, max\_amin_a,max_a,數(shù)組sum_bsum\_bsum_b的前綴最小,前綴最大值數(shù)組為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)。
所以有一個(gè)較為暴力的算法 二分 + 線段樹 去checkcheckcheck答案,當(dāng)時(shí)這樣操作復(fù)雜度是O(nlog?2n)O(n \log ^ 2 n)O(nlog2n)的,對(duì)于n=106n = 10 ^ 6n=106的數(shù)據(jù)顯然是不可行的。
考慮線段樹上二分:
假設(shè)當(dāng)前答案在區(qū)間為[l,r][l, r][l,r],如果答案在[mid+1,r][mid + 1, r][mid+1,r]上,一定有[1,mid][1, mid][1,mid]這段區(qū)間的前綴最大,前綴最小得到的兩個(gè)區(qū)間是不相交的,
另開四個(gè)變量來記錄區(qū)間[1,l?1][1, l - 1][1,l?1]中AAA的前綴最小, 最大,BBB的前綴最小,最大,
用這四個(gè)變量跟區(qū)間[l,mid][l, mid][l,mid]的最大最小來判斷,答案是否落在[l,mid][l, mid][l,mid]之間,直到遞歸到葉節(jié)點(diǎn),進(jìn)行判斷是否符合條件即可。
#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; }總結(jié)
以上是生活随笔為你收集整理的L 苍天阻我寻你,此情坚贞如一(西南科技大学2021届新生赛)(线段树)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: E速度即转发(牛客挑战赛48)(树套树)
- 下一篇: 冰糖雪梨莲子汤的功效与作用、禁忌和食用方