A. Rooms and Passages【区间问题】

题目链接:https://codeforces.com/gym/102215/problem/A

题目:
There are (n+1) rooms in the dungeon, consequently connected by n passages. The rooms are numbered from 0 to n, and the passages — from 1 to n. The i-th passage connects rooms (i−1) and i.

Every passage is equipped with a security device of one of two types. Security device of the first type checks if a person who walks through the passage has the pass of the certain color, and forbids movement if such pass is invalid. Security device of the second type never forbids movement, but the pass of the certain color becomes invalid after the person walks through.

In the beginning you are located in the room s and have all the passes. For every s from 0 to (n−1) find how many rooms you can walk through in the direction of the room n.

Input
The first line contains an integer n (1≤n≤500000) — the number of passages.

The second line contains n integers ai (1≤|ai|≤n). The number |ai| is a color of the pass which the i-th passage works with. If ai>0, the i-th passage is the first type passage, and if ai<0 — the second type.

Output
Output n integers: answers for every s from 0 to (n−1).

Examples
inputCopy
6
1 -1 -1 1 -1 1
outputCopy
3 2 1 2 1 1
inputCopy
7
2 -1 -2 -3 1 3 2
outputCopy
4 3 3 2 3 2 1

题目大意:

	面前有n+1个房间,n个门,门有两种:正数门需要你拥有对应数字的钥匙才能通过,负数门随便通过,但是会夺走对应数字的钥匙。问分别在0到n-1作为起点,各自走的最远距离。

这是一个区间问题,我的原始想法非常暴力,用used存钥匙的情况,然后从开始遍历,遇到正数,ans[time]=ans[time-1],遇到负数就往后查。

这种无脑往后面推进的做法直接导致了我的代码的长度,复杂度都上升了,虽然做法得证是正确的,但是因为过于复杂难以纠错,在17th个test就卡住了。

然后看了一下别人的代码发现别人是从反向遍历的,而且没有用到used数组,而是使用了一一对应的位置数组:

遇到正数就更新first[a[time]]=time;
遇到负数就查if(first[-a[time]]!=0)right=min(right,first[-a[time]]);

用right表示最远可达的位置,每次遇到负数,而且他的first数组的数字是一个非零数,就更新right的数值。

最后因为right是最远可达位置,我们每次反向遍历中就可以让ans[time]=right-time;

重点在于保证了right切切实实是最远可达的位置。

const int MAXN=5e5+10;
int a[MAXN],first[MAXN],ans[MAXN];
int main()
{
	int n;
	cin>>n;
	int right=n;
	for(int time=0;time<n;time++)cin>>a[time];
	for(int time=n-1;time>=0;time--)
	{
		if(a[time]>0)first[a[time]]=time;
		else
		{
			if(first[-a[time]]!=0)right=min(right,first[-a[time]]);
		}
		ans[time]=right-time;
	}
	for(int time=0;time<n;time++)cout<<ans[time]<<' ';
	cout<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值