首先建反向边。
然后奇偶分成两派,进行两次bfs,更新能到的点的步数 。
因为偶数点要由奇数来更新,所以最后更新的时候奇数点在偶数的距离里找,偶数在奇数里面找。
为什么bfs可以呢,以跑奇数为例,第一遍时,我们把一步可以到的偶数点都更新了,那后面的偶数点要更新时只能通过前面能到的偶数点去更新,路径也就是奇偶偶偶偶…
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<map>
using namespace std;
#define LL long long
#define eps (1e-8)
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
struct node
{
int v, nxt;
}e[maxn << 1];
int a[maxn], head[maxn], cnt;
void add(int u, int v)
{
e[++cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
queue<int>odd, even;
int v1[maxn], v2[maxn], dist1[maxn], dist2[maxn];
void bfs1()
{
while (!odd.empty())
{
int u = odd.front();
odd.pop();
v1[u] = 0;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v;
if (!v1[v])
{
if (dist1[v] > dist1[u] + 1)
{
dist1[v] = dist1[u] + 1;
odd.push(v);
}
}
}
}
}
void bfs2()
{
while (!even.empty())
{
int u = even.front();
even.pop();
v2[u] = 0;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v;
if (!v2[v])
{
if (dist2[v] > dist2[u] + 1)
{
dist2[v] = dist2[u] + 1;
even.push(v);
}
}
}
}
}
int main()
{
memset(dist1, inf, sizeof(dist1));
memset(dist2, inf, sizeof(dist2));
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
if (i - a[i] >= 1)add(i - a[i], i);
if (i + a[i] <= n)add(i + a[i], i);
if (a[i] % 2)
{
odd.push(i);
v1[i] = 1;
dist1[i] = 0;
}
else
{
even.push(i);
v2[i] = 1;
dist2[i] = 0;
}
}
bfs1();
bfs2();
for (int i = 1; i <= n; i++)
{
if (a[i] % 2)
{
if (dist2[i] == inf)printf("-1 ");
else printf("%d ", dist2[i]);
}
else
{
if (dist1[i] == inf)printf("-1 ");
else printf("%d ", dist1[i]);
}
}
cout << endl;
return 0;
}