codeforces 498 d Traffic Jams in the Land

本文介绍了一个涉及城市间交通堵塞问题的算法竞赛题目,使用线段树来解决从一个城市到另一个城市的最短路径计算问题,并在特定条件下更新道路状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

codeforces 498 d Traffic Jams in the Land

题目链接

点击打开链接

题意:有n+1个城市,n条路,每条路连着第n个和第n+1个城市,然后每条路有一个路况信息a[i],如果现在的时刻t,t%a[i]==0,则不能通过这条路,要等到下一秒t+1,如果现在时刻t,t%a[i]!=0,则通过这条路,花费时间为1。现在有q个操作,对于每个操作有两种类型:

A x y 询问从城市x到城市y要花费多少时间
C x y 把a[x]改为y
限制:1 <= n <= 1e5 , 2 <= ai <= 6 , 1 <= q <= 1e5
思路:线段树
要解决的问题是O(logn)查询出来从x到y的时间。
因为ai只有 2 3 4 5 6 这几个取值,最小公倍数为60,也就是说无论是哪段路都可以以60为周期。
所以对路建树
线段树里面有一个t[60]的数组,表示在l城市在t时刻出发到r+1城市要花的时间。

考虑好向上维护的情况就能过了。

/*cf284div1d
  题意:有n+1个城市,n条路,每条路连着第n个和第n+1个城市,然后每条路有一个路况信息a[i],如果现在的时刻t,t%a[i]==0,则不能通过这条路,要等到下一秒t+1,如果现在时刻t,t%a[i]!=0,则通过这条路,花费时间为1。现在有q个操作,对于美国操作有两种类型:
  A x y 询问从城市x到城市y要花费多少时间
  C x y 把a[x]改为y
  限制:1 <= n <= 1e5 , 2 <= ai <= 6 , 1 <= q <= 1e5
  思路:线段树
  要解决的问题是O(logn)查询出来从x到y的时间。
  因为ai只有 2 3 4 5 6 这几个取值,最小公倍数为60,也就是说无论是哪段路都可以以60为周期。
  所以对路建树
  线段树里面有一个t[60]的数组,表示在l城市在t时刻出发到r+1城市要花的时间。
  考虑好向上维护的情况就能过了。
 */
#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005;
int a[N];
struct Seg{
	int l,r,mid;
	int t[60];
}seg[3*N];
void up(int n){
	for(int i=0;i<60;++i){
		int tmp=i+seg[2*n].t[i];	//注意的地方
		seg[n].t[i]=tmp-i+seg[2*n+1].t[tmp%60];
	}
}
void build(int l,int r,int n){
	seg[n].l=l; seg[n].r=r; seg[n].mid=(l+r)>>1;
	if(l==r){
		for(int i=0;i<60;++i)
			if(i%a[l]==0) seg[n].t[i]=2;
			else seg[n].t[i]=1;
		return ;
	}
	build(l,seg[n].mid,2*n);
	build(seg[n].mid+1,r,2*n+1);
	up(n);
}
void update(int u,int n,int x){
	if(seg[n].l==seg[n].r){
		a[u]=x;
		for(int i=0;i<60;++i)
			if(i%a[u]==0) seg[n].t[i]=2;
			else seg[n].t[i]=1;
		return ;
	}
	if(u<=seg[n].mid) update(u,2*n,x);
	else update(u,2*n+1,x);
	up(n);
}
int query(int l,int r,int n,int t){
	if(l <= seg[n].l && seg[n].r <= r){
		return t+seg[n].t[t%60];
	}
	if(seg[n].mid>=l) t=query(l,r,2*n,t);
	if(seg[n].mid<r) t=query(l,r,2*n+1,t);
	return t;
}
void debug(int n){
	cout<<"---"<<endl;
	for(int i=1;i<=n;++i)
		cout<<query(i,i,1,0)<<' ';
	cout<<endl;
	cout<<"---"<<endl;
}
void debug1(int n){
	cout<<seg[n].l<<' '<<seg[n].r<<' '<<seg[n].t[0]<<endl;
	if(seg[n].l==seg[n].r) return ;
	debug1(2*n);
	debug1(2*n+1);
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d",&a[i]);
	build(1,n,1);
	int m;
	scanf("%d",&m);
	char op[2];
	int u,v;
	for(int i=0;i<m;++i){
		scanf("%s%d%d",op,&u,&v);
		if(op[0]=='A'){
			printf("%d\n",query(u,v-1,1,0));
		}
		else{
			update(u,1,v);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值