题目大意:
一段路上有
N
N
N 个点,每个点有一个合法时间段
[
u
i
,
v
i
]
[u_i, v_i]
[ui,vi],相邻两个点有一个长度。每次问,在
u
i
u_i
ui 的时间从 i 出发后,能否依次经过
i
+
1
i+1
i+1 ~
j
j
j 的所有点,使得到达时间满足每个点的合法区间(如果提前到可以等待,迟到了失败了)。同时还可能修改一段路的长度,或者修改一个点的合法时间段。
N
,
Q
<
=
1000000
N, Q <= 1000000
N,Q<=1000000
解题思路:
- 考虑 (l, r) 的询问所有的限制条件。我们以 (1, 3) 举例,即:
𝑢 1 ≤ 𝑣 1 , m a x ( 𝑢 1 + 𝑑 1 , 𝑢 2 ) ≤ 𝑣 2 , m a x ( m a x ( 𝑢 1 + 𝑑 1 , 𝑢 2 ) + 𝑑 2 , 𝑢 3 ) ≤ 𝑣 3 𝑢_1≤𝑣_1,max(𝑢_1+𝑑_1,𝑢_2 )≤𝑣_2,max(max(𝑢_1+𝑑_1,𝑢_2 )+𝑑_2, 𝑢_3 )≤𝑣_3 u1≤v1,max(u1+d1,u2)≤v2,max(max(u1+d1,u2)+d2,u3)≤v3
现在我们设 𝑢 𝑖 ′ = 𝑢 𝑖 + 𝑑 𝑖 + 𝑑 ( 𝑖 + 1 ) + … + 𝑑 ( 𝑛 − 1 ) , 𝑣 𝑖 ′ = 𝑣 𝑖 + 𝑑 𝑖 + 𝑑 ( 𝑖 + 1 ) + … + 𝑑 ( 𝑛 − 1 ) 𝑢_𝑖^′=𝑢_𝑖+𝑑_𝑖+𝑑_(𝑖+1)+…+𝑑_(𝑛−1),𝑣_𝑖^′=𝑣_𝑖+𝑑_𝑖+𝑑_(𝑖+1)+…+𝑑_(𝑛−1) ui′=ui+di+d(i+1)+…+d(n−1),vi′=vi+di+d(i+1)+…+d(n−1)
现在 (l, r) 的限制变成了:
𝑢 1 ′ ≤ 𝑣 1 ′ , m a x ( 𝑢 1 ′ , 𝑢 2 ′ ) ≤ 𝑣 2 ′ , m a x ( 𝑢 1 ′ , 𝑢 2 ′ , 𝑢 3 ′ ) ≤ 𝑣 3 ′ 𝑢_1^′≤𝑣_1^′,max(𝑢_1^′,𝑢_2^′ )≤𝑣_2^′,max(𝑢_1^′, 𝑢_2^′,𝑢_3^′ )≤𝑣_3^′ u1′≤v1′,max(u1′,u2′)≤v2′,max(u1′,u2′,u3′)≤v3′
线段树维护当前区间是否可行、u 的最大值和 v 的最小值,复杂度是 𝑂 ( 𝑁 l o g 𝑁 ) 𝑂(𝑁 log 𝑁) O(NlogN)。 - 合并区间时,要两个子区间都可行且左子区间的u最大值小于右子区间的v的最小值,当前区间才可行,否则不可行
- 当更新 u i , v i u_i,v_i ui,vi时只要单点修改就行了
- 当更新 d i d_i di时,要对 1 1 1~ i i i进行区间修改即可
AC代码
#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
const int maxn = 1e6 + 10;
typedef long long ll;
const ll inf = 0x3f3f3f3f;
struct Trip {
ll umax, vmin;
bool ok;
} tree[maxn << 2];
ll lazy[maxn << 2];
int n;
ll sumd[maxn], u[maxn], v[maxn], d[maxn];
inline int ls(int rt) {return rt << 1;}
inline int rs(int rt) {return rt << 1 | 1;}
void pushup(int rt) {
tree[rt].umax = max(tree[ls(rt)].umax, tree[rs(rt)].umax);
tree[rt].vmin = min(tree[ls(rt)].vmin, tree[rs(rt)].vmin);
if (tree[ls(rt)].ok == true && tree[rs(rt)].ok == true && tree[ls(rt)].umax <= tree[rs(rt)].vmin)
tree[rt].ok = true;
else
tree[rt].ok = false;
}
void pushdown(int rt) {
tree[ls(rt)].umax += lazy[rt];
tree[ls(rt)].vmin += lazy[rt];
lazy[ls(rt)] += lazy[rt];
tree[rs(rt)].umax += lazy[rt];
tree[rs(rt)].vmin += lazy[rt];
lazy[rs(rt)] += lazy[rt];
lazy[rt] = 0;
}
void build(int lc, int rc, int rt) {
lazy[rt] = 0;
if (lc == rc) {
tree[rt] = {u[lc], v[lc], true};
return;
}
int mc = (lc + rc) >> 1;
build(lc, mc, ls(rt));
build(mc + 1, rc, rs(rt));
pushup(rt);
}
void Pot_Add1(int x, ll y, int lc, int rc, int rt) {
if (lc == rc) {
tree[rt].umax += y;
return;
}
pushdown(rt);
int mc = (lc + rc) >> 1;
if (x <= mc) Pot_Add1(x, y, lc, mc, ls(rt));
else Pot_Add1(x, y, mc + 1, rc, rs(rt));
pushup(rt);
}
void Pot_Add2(int x, ll y, int lc, int rc, int rt) {
if (lc == rc) {
tree[rt].vmin += y;
return;
}
pushdown(rt);
int mc = (lc + rc) >> 1;
if (x <= mc) Pot_Add2(x, y, lc, mc, ls(rt));
else Pot_Add2(x, y, mc + 1, rc, rs(rt));
pushup(rt);
}
void Seg_Add(int L, int R, ll z, int lc, int rc, int rt) {
if (R < lc || rc < L) return;
if (L <= lc && rc <= R) {
tree[rt].umax += z;
tree[rt].vmin += z;
lazy[rt] += z;
return;
}
pushdown(rt);
int mc = (lc + rc) >> 1;
Seg_Add(L, R, z, lc, mc, ls(rt));
Seg_Add(L, R, z, mc + 1, rc, rs(rt));
pushup(rt);
}
Trip Query(int L, int R, int lc, int rc, int rt) {
if (R < lc || rc < L) return {-inf, inf, true};
if (L <= lc && rc <= R) {
return tree[rt];
}
pushdown(rt);
int mc = (lc + rc) >> 1;
Trip res1 = Query(L, R, lc, mc, ls(rt));
Trip res2 = Query(L, R, mc + 1, rc, rs(rt));
pushup(rt);
Trip res;
if (res1.ok == true && res2.ok == true && res1.umax <= res2.vmin) res = {max(res1.umax, res2.umax), min(res1.vmin, res2.vmin), true};
else res = {max(res1.umax, res2.umax), min(res1.vmin, res2.vmin), false};
return res;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int _, q;
cin >> _;
while (_--) {
cin >> n;
for (int i = 1; i <= n; i++) cin >> u[i];
for (int i = 1; i <= n; i++) cin >> v[i];
for (int i = 1; i < n; i++) cin >> d[i];
sumd[n] = 0;
for (int i = n - 1; i >= 1; i--) sumd[i] = sumd[i + 1] + d[i];
for (int i = 1; i <= n; i++) u[i] = u[i] + sumd[i], v[i] = v[i] + sumd[i];
build(1, n, 1);
cin >> q;
int op;
ll x, y, z;
bool ok;
while (q--) {
cin >> op;
if (op == 0) {
cin >> x >> y;
ok = Query(x, y, 1, n, 1).ok;
if (ok) puts("Yes");
else puts("No");
}
else if (op == 1) {
cin >> x >> y;
Seg_Add(1, x, y - d[x], 1, n, 1);
d[x] = y;
}
else {
cin >> x >> y >> z;
Pot_Add1(x, y + sumd[x] - u[x], 1, n, 1);
Pot_Add2(x, z + sumd[x] - v[x], 1, n, 1);
u[x] = y + sumd[x], v[x] = z + sumd[x];
}
}
}
}
/*
1
5
85 71 79 41 54
91 83 99 43 69
7 1 3 2
3
1 5 8
2 2 7 13
0 3 5
1
5
85 71 79 41 54
91 83 99 43 69
7 1 3 2
2
2 2 7 13
0 3 5
1
5
85 71 79 41 54
91 83 99 43 69
7 1 3 2
2
1 5 8
0 3 5
1
5
85 71 79 41 54
91 83 99 43 69
7 1 3 2
1
0 3 5
*/