【Nowcoder】2021牛客暑假集训营(第一场):Journey among Railway Stations 线段树 + 节点合并

传送门

题意

一段路上有 N N N 个点,每个点有一个合法时间段 [ u i , v i ] [u_i, v_i] [ui,vi],相邻两个点有一个长度。每次问,在 u_i 的时间从 i 出发后,能否依次经过 i + 1 ∼ j i+1 \sim j i+1j 的所有点,使得到达时间满足每个点的合法区间(如果提前到可以等待,迟到了失败了)。同时还可能修改一段路的长度,或者修改一个点的合法时间段。

分析

我们去用线段树维护每一段最后离开的最早时间,最晚时间,然后去和其他的节点进行合并,通过距离和时间范围判断是否合法
最后修改因为是单点修改,暴力修改即可
需要注意的是父节点与两个子节点的关系并不是简单的逻辑关系,所以在 q u e r y query query的时候需要将所有范围合并成一个节点返回

代码

#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
#define _CRT_SECURE_NO_WARNINGS
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10;
const ll mod = 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a) {
	char c = getchar(); T x = 0, f = 1; while (!isdigit(c)) {if (c == '-')f = -1; c = getchar();}
	while (isdigit(c)) {x = (x << 1) + (x << 3) + c - '0'; c = getchar();} a = f * x;
}
int gcd(int a, int b) {return (b > 0) ? gcd(b, a % b) : a;}

struct Node{
	int l,r;
	int u,v,w;
	bool f;
}tr[N * 4];
int U[N],V[N],w[N];
int n;

Node merge(Node l,Node r,int cost)
{
    Node ans;
    ans.f= l.f&r.f;
    if(l.u+cost> r.v) ans.f=0;
    ans.u=max(r.u,l.u+cost+r.w);
    ans.v=min(l.v,r.v-cost-l.w);
    ans.w=l.w+r.w+cost;
    return ans;
}

void build(int u,int l,int r){
	tr[u] = {l,r};
	if(l == r){
		tr[u] = {l,r,U[l],V[l],0,1};
		return;
	}
	int mid = l + r >> 1;
	build(u << 1,l,mid);
	build(u << 1 | 1,mid + 1,r);
	tr[u] = merge(tr[u << 1],tr[u << 1 | 1],w[mid]);
}

Node query(int u,int l,int r){
	if(tr[u].l >= l && tr[u].r <= r) return tr[u];
	int mid = tr[u].l + tr[u].r >> 1;
	if(r <= mid) return query(u << 1,l,r);
	else if(l > mid) return query(u << 1 | 1,l,r);
	else return(merge(query(u << 1,l,r),query(u << 1 | 1,l,r),w[mid]));
}

void modify(int u,int p){
	if(tr[u].l == tr[u].r){
		tr[u] = {p,p,U[p],V[p],0,1};
		return;
	}
	int mid = tr[u].l + tr[u].r >> 1;
	if(p <= mid) modify(u << 1,p);
	else modify(u << 1 | 1,p);
	tr[u] = merge(tr[u << 1],tr[u << 1 | 1],w[mid]);
}

int main() {
	int T;
	read(T);
	while(T--){
		read(n);
		for(int i = 1;i <= n;i++) read(U[i]);
		for(int i = 1;i <= n;i++) read(V[i]);
		for(int i = 1;i < n;i++) read(w[i]);
		build(1,1,n);
		int q;
		read(q);
		while(q--){
			int op;
			read(op);
			if(!op){
				int l,r;
				read(l),read(r);
				if(query(1,l,r).f) puts("Yes");
				else puts("No");
			}
			else if(op == 1){
				int p;
				read(p),read(w[p]);
				modify(1,p);
			}
			else{
				int p;
				read(p);
				read(U[p]),read(V[p]);
				modify(1,p);
			}
		}

	}
	return 0;
}

/**
*  ┏┓   ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃       ┃
* ┃   ━   ┃ ++ + + +
*  ████━████+
*  ◥██◤ ◥██◤ +
* ┃   ┻   ┃
* ┃       ┃ + +
* ┗━┓   ┏━┛
*   ┃   ┃ + + + +Code is far away from  
*   ┃   ┃ + bug with the animal protecting
*   ┃    ┗━━━┓ 神兽保佑,代码无bug 
*   ┃        ┣┓
*    ┃        ┏┛
*     ┗┓┓┏━┳┓┏┛ + + + +
*    ┃┫┫ ┃┫┫
*    ┗┻┛ ┗┻┛+ + + +
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值