2021牛客暑期多校训练营1:J-Journey among Railway Stations

题目链接

题意:有n个火车站点,第i个站点可以入站出站的时间为[ui,vi],到达下一站需要时间cost[i],需要我们实现三种操作:①询问从站点1出发,能否顺利通过l,l+1,…,r站点②修改cost[i]的值③修改ui,vi的值

解法:线段树,没什么可展开讲的,看代码就可以理解了
节点形式为:

struct node {
	int flag;
	ll minx, maxy, usetime;
};

flag:次节点能否通过
minx:这个节点到达下一站的最早时间
maxy:到达这个节点允许的最晚时间

AcCode

#include<algorithm>
#include<iostream>
#include<cstdio>

#define ll long long

using namespace std;

const int N = 1000005;

struct node {
	int flag;
	ll minx, maxy, usetime;
};

node point[N * 4];

int u[N], v[N], cost[N];

inline ll min(ll a, ll b) { return (a < b) ? a : b; }
inline ll max(ll a, ll b) { return (a > b) ? a : b; }
inline int lc(int x) { return x * 2; }
inline int rc(int x) { return (x * 2 + 1); }

inline node marge(node a, node b) {
	node ret;
	if (b.maxy < a.minx) ret.flag = 0;
	else ret.flag = (a.flag & b.flag);
	ret.usetime = a.usetime + b.usetime;//路上花费时间
	ret.minx = max(a.minx + b.usetime, b.minx);//到达下一站的最小时间
	ret.maxy = min(a.maxy, b.maxy - a.usetime);//最晚进站时间
	return ret;

}

inline void build(int now, int l, int r) {
	if (l == r) {
		point[now].flag = 1;
		point[now].minx = u[l] + cost[l];
		point[now].maxy = v[l];
		point[now].usetime = cost[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(lc(now), l, mid);
	build(rc(now), mid + 1, r);
	point[now] = marge(point[lc(now)], point[rc(now)]);
}

inline node query(int now, int l, int r, int ql, int qr) {
	//if(point[now].flag) return point[now];//返回后还要合并
	if (ql <= l && qr >= r) return point[now];
	int mid = (l + r) >> 1;
	if (qr <= mid) return query(lc(now), l, mid, ql, qr);
	else if (ql > mid) return query(rc(now), mid + 1, r, ql, qr);
	else return marge(query(lc(now), l, mid, ql, qr), query(rc(now), mid + 1, r, ql, qr));
	return point[now];
}

inline void changCost(int now, int l, int r, int index) {
	if (l == r) {
		point[now].flag = 1;
		point[now].usetime = cost[l];
		point[now].minx = u[l] + cost[l];
		point[now].maxy = v[l];
		return;
	}
	int mid = (l + r) >> 1;
	if (index <= mid) changCost(lc(now), l, mid, index);
	else changCost(rc(now), mid + 1, r, index);
	point[now] = marge(point[lc(now)], point[rc(now)]);
}


signed main() {
	//std::ios::sync_with_stdio(false);
	//std::cin.tie(0);
	int t;
	scanf("%d", &t);
	//std::cin >> t;
	while (t--) {
		int n;
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) scanf("%d", &u[i]);
		for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
		for (int i = 1; i < n; i++) scanf("%d", &cost[i]);
		build(1, 1, n);
		int q;
		scanf("%d", &q);
		while (q--) {
			int sign;
			scanf("%d", &sign);
			if (sign == 0) {
				int ql, qr; scanf("%d %d", &ql, &qr);
				if (query(1, 1, n, ql, qr).flag)printf("Yes\n");
				else printf("No\n");
			}
			else if (sign == 1) {
				int index, val; scanf("%d %d", &index, &val);
				cost[index] = val;
				changCost(1, 1, n, index);
			}
			else {
				int index, p, q; scanf("%d %d %d", &index, &p, &q);
				u[index] = p;
				v[index] = q;
				changCost(1, 1, n, index);
			}
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值