题目大意:
一段路上有 N N N 个点,每个点有一个合法时间段 [ u i , v i ] [u_i,v_i] [ui,vi],相邻两个点有一个长度 w i w_i wi。有 q q q次询问,每次询问,在 [ u i , v i ] [u_i,v_i] [ui,vi]的时间段从 i i i出发后,能否依次经过 i + 1 到 j i+1到j i+1到j的所有点,使得到达时间满足每个点的合法区间(如果提前到可以等待,迟到了失败了)。同时还可能修改一段路的长度,或者修改一个点的合法时间段。
N , q ∈ [ 1 , 1 e 6 ] N,q\in[1,1e6] N,q∈[1,1e6]
解题思路:
-
从 [ l , l + 1 , l + 2.... + r − 1 , r ] [l,l+1,l+2....+r-1,r] [l,l+1,l+2....+r−1,r]实际上我们可以这么来看,我们先把 [ u l , v l ] + w l → [ u l + w l , v l + w l ] [u_l,v_l]+w_l\rightarrow[u_l+w_l,v_l+w_l] [ul,vl]+wl→[ul+wl,vl+wl]然后和 [ u l + 1 , v l + 1 ] [u_{l+1},v_{l+1}] [ul+1,vl+1]求区间交
-
但是不是简单的区间交,因为是可以的等待的,那么就是左端点取 m a x max max,但是右端点还是取 v l + 1 v_{l+1} vl+1
-
区间就变成了 [ m a x ( u l + w l , u l + 1 ) , v l + 1 ] [max(u_l+w_l,u_{l+1}),v_{l+1}] [max(ul+wl,ul+1),vl+1]然后再把这个区间加 w l + 1 w_{l+1} wl+1去迭代(假设相交部分是绿色的)
-
但是我们不可能每次都把绿色拿出来那么我们可以直接把 L L L区间和 L + 1 L+1 L+1的区间直接拿去和 L + 2 L+2 L+2区间相交,现在就是蓝色的部分啦,就是三个区间交!
- 我们发现就是对于把 L L L和 L + 1 L+1 L+1区间 a d d ( w l + 1 ) add(w_{l+1}) add(wl+1)和 L + 2 L+2 L+2交对于 L L L是加上 w l + w l + 1 w_l+w_{l+1} wl+wl+1
- 实际上就是加上 w i w_i wi的后缀和就可以了 [ u L , v L ] + w l + . . . . w n − 1 [u_L,v_L]+w_l+....w_{n-1} [uL,vL]+wl+....wn−1
- 那么所以的 [ 1 , n ] 的 时 间 段 就 变 成 了 [ u i + w i + . . . + w n − 1 , v i + w i + . . . + w n − 1 ] [1,n]的时间段就变成了[u_i+w_i+...+w_{n-1},v_i+w_i+...+w_{n-1}] [1,n]的时间段就变成了[ui+wi+...+wn−1,vi+wi+...+wn−1]
- 那么是不是判断这 [ l , r ] [l,r] [l,r]里面区间是否有没有交集呢?
- 不是!!假设我们处理后的区间长 [ l , l + 4 ] [l,l+4] [l,l+4]长这样
- 对于任意的标号小于自己的区间只能小于自己,就是 u j ≤ v i [ j ≤ i ] u_j\leq v_i[j\leq i] uj≤vi[j≤i]!! 因为可以等待!!
- 那就是线段树了!!
- 叶子节点维护区间左端点的最大值 l m a x lmax lmax和右端点最小值 r m i n rmin rmin
- 合并的时候判断左区间的左端点的最大值和右区间右端点的最小值就可以了
- 一个ok表示下面的区间是否合法(就是是否可以在任意站停靠)
- 区间修改 w i w_i wi,因为修改一个 w i w_i wi影响了线段树里面 [ 1 , i ] [1,i] [1,i]里面所以点的权值和单点修改 [ u l , v l ] [u_l,v_l] [ul,vl]只对特定点修改了
AC code
O ( n l o g n ) O(nlogn) O(nlogn)
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define endl '\n'
using namespace std;
const int maxn = 1000010;
typedef long long ll;
typedef pair<ll,ll> PLL;
int n;
struct inf {ll lmax, rmin;bool ok;};
PLL seg[maxn];
ll w[maxn], pre[maxn];
struct node {
ll lmax[maxn << 2];
ll rmin[maxn << 2];
ll tag[maxn << 2];
bool ok[maxn << 2];
inline void pushup(int rt) {
lmax[rt] = max(lmax[rt<<1],lmax[rt<<1|1]);
rmin[rt] = min(rmin[rt<<1],rmin[rt<<1|1]);
if((lmax[rt<<1] > rmin[rt<<1|1]) || ok[rt<<1] || ok[rt<<1|1]) ok[rt] = 1;// 合并判断
else ok[rt] = 0;
}
inline void pushdown(int rt) {
tag[rt<<1] += tag[rt];
tag[rt<<1|1] += tag[rt];
lmax[rt<<1] += tag[rt];
lmax[rt<<1|1] += tag[rt];
rmin[rt<<1] += tag[rt];
rmin[rt<<1|1] += tag[rt];
tag[rt] = 0;
}
void build(int rt, int l, int r) {
tag[rt] = 0;
ok[rt] = 0;
if(l == r) {
lmax[rt] = pre[l] + seg[l].first;
rmin[rt] = pre[l] + seg[l].second;
return;
}
build(Lson);
build(Rson);
pushup(rt);
}
void update(int rt ,int l, int r, int posl, int posr, int val, int ok) {
if(posl <= l && posr >= r) {
tag[rt] += val;
if(ok==0) lmax[rt] += val;// 单点修改判断是改哪个?
else if(ok==1)rmin[rt] += val;
else lmax[rt] += val, rmin[rt] += val;
return;
}
pushdown(rt);
if(posl <= mid) update(Lson,posl,posr,val,ok);
if(posr > mid) update(Rson,posl,posr,val,ok);
pushup(rt);
}
inf ask(int rt, int l, int r, int posl, int posr) {
if(posl <= l && posr >= r) return {lmax[rt],rmin[rt],ok[rt]};
pushdown(rt);
inf resl = {(ll)-1e18,(ll)1e18,0};
inf resr = {(ll)-1e18,(ll)1e18,0};
if(posl <= mid) resl = ask(Lson,posl,posr);
if(posr > mid) {
resr = ask(Rson,posl,posr);
resr.ok |= ((resl.lmax > resr.rmin) | resl.ok); // 合并的时候判断
resr.lmax = max(resl.lmax,resr.lmax);
resr.rmin = min(resl.rmin,resr.rmin);
return resr;
}
return resl;
}
}sgt;
int main() {
IOS;
int _;
cin >> _;
while(_--) {
cin >> n;
for(int i = 1; i <= n; ++ i) cin >> seg[i].first;
for(int i = 1; i <= n; ++ i) cin >> seg[i].second;
for(int i = 1; i < n; ++ i) cin >> w[i];
pre[n] = 0;
for(int i = n-1; i >= 1; -- i) pre[i] = w[i] + pre[i+1];//求个后缀和
sgt.build(1,1,n);
int q;
cin >> q;
while(q--) {
int op, l, r, val;
cin >> op >> l >> r;
if(op == 0) {
inf res = sgt.ask(1,1,n,l,r);
if(res.ok) cout << "No\n";
else cout << "Yes\n";
} else if(op == 1) {
sgt.update(1,1,n,1,l,r-w[l],2);
w[l] = r;// 注意更新
} else {
cin >> val;
sgt.update(1,1,n,l,l,r-seg[l].first,0);
sgt.update(1,1,n,l,l,val-seg[l].second,1);
seg[l].first = r;
seg[l].second = val;// 注意更新
}
}
}
}