题解 | #Journey among Railway Stations#
Alice and Bob
https://ac.nowcoder.com/acm/contest/11166/A
J - Journey among Railway Stations
题意:个点,每个点的合法时间是
,第i个点到下一个点的需要的最短时间为
,每次询问从
点出发到r点是否合法,或者修改
值,
、
值。
思路:
要从点到点
,可以列出式子
在合法情况下,如果到不了
,那么就直接取到
,否则就取
。也就是说,我要在前面找一个点,这个点到当前点需要的最小时间最大,再判断当前的合法性。
设点和点
,点
到点
时的最小时间是
,点
到点
的最小时间是
。一路加过来显然不合理,除自身点值外,两者仅相差
,也看出了两者的
左端点是确定的,但是右端点会随着点
的改变而改变,那么不如将所有点的右端点均设为
,把所有
和
都加上相应的
,变成
和
,重新带回到上式,发现变成了
这个式子就很容易用线段树来维护了。线段树里维护的最大值,
的最小值,以及当前的合法性。
#include <bits/stdc++.h> using namespace std; #define ls (id << 1) #define rs (id << 1 | 1) #define mid (l + r >> 1) inline int rd() { int f = 0; int x = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) f |= (ch == '-'); for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; if (f) x = -x; return x; } typedef long long ll; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3f; const int N = 1e6 + 7; ll u[N], v[N], c[N], pre[N]; int n; struct Seg{ struct node{ bool ok; ll uu, vv, add; }t[N << 2]; node merge(node ln, node rn) { node tmp = ln; tmp.ok &= rn.ok; if (ln.uu > rn.vv) tmp.ok = false; tmp.uu = max(tmp.uu, rn.uu); tmp.vv = min(tmp.vv, rn.vv); tmp.add = 0; return tmp; } void up(int id) { t[id] = merge(t[ls], t[rs]); } void down(int id) { if (t[id].add == 0) return; ll add = t[id].add; t[ls].add += add, t[ls].uu += add, t[ls].vv += add; t[rs].add += add, t[rs].uu += add, t[rs].vv += add; t[id].add = 0; } void build(int id, int l, int r) { if (l == r) { t[id].add = 0; t[id].ok = true; t[id].uu = u[l] + pre[n] - pre[l - 1]; t[id].vv = v[l] + pre[n] - pre[l - 1]; return; } build(ls, l, mid); build(rs, mid + 1, r); up(id); } void modify(int id, int l, int r, int ql, int qr, int pu, int pv, ll pa) { if (l >= ql && r <= qr) { if (pu != 0) { t[id].uu += pu - u[l]; t[id].vv += pv - v[l]; u[l] = pu, v[l] = pv; } else { t[id].add += pa; t[id].uu += pa; t[id].vv += pa; } return; } down(id); if (ql <= mid) modify(ls, l, mid, ql, qr, pu, pv, pa); if (qr > mid) modify(rs, mid + 1, r, ql, qr, pu, pv, pa); up(id); } node query(int id, int l, int r, int ql, int qr) { if (l >= ql && r <= qr) return t[id]; down(id); bool flag = 0; node tmp; if (ql <= mid) { flag = 1; tmp = query(ls, l, mid, ql, qr); } if (qr > mid) { if (!flag) tmp = query(rs, mid + 1, r, ql, qr); else tmp = merge(tmp, query(rs, mid + 1, r, ql, qr)); } return tmp; } ll getOk(int ql, int qr) { node tmp = query(1, 1, n, ql, qr); return tmp.ok; } }seg; void solve() { n = rd(); for (int i = 1; i <= n; ++i) { u[i] = rd(); } for (int i = 1; i <= n; ++i) { v[i] = rd(); } for (int i = 1; i < n; ++i) { c[i] = rd(); } for (int i = 1; i <= n; ++i) { pre[i] = c[i] + pre[i - 1]; } seg.build(1, 1, n); int q = rd(); while (q--) { int op = rd(); if (op == 0) { int ql = rd(), qr = rd(); if (seg.getOk(ql, qr)) puts("Yes"); else puts("No"); } else if (op == 1) { int i = rd(), w = rd(); seg.modify(1, 1, n, 1, i, 0, 0, w - c[i]); c[i] = w; } else { int i = rd(), pu = rd(), pv = rd(); seg.modify(1, 1, n, i, i, pu, pv, 0); } } } int main() { int t = 1; t = rd(); while (t--) solve(); return 0; }