奇怪的最短路

Description

给定长度为 nn 的数列 aa ,如果 ai​ & aj0a_i​ \ \& \ a_j ​\ne 0(按位与),则在 i,ji,j 之间存在一条长度为 ai+aja_i​ + a_j​ 的边,求 11 至所有点的最短路。

Input

第一行一个正整数 nn 。 接下来一行 n 个整数 a1ana_1​∼a_n​

Output

输出一行 n 个整数,第 i 个为 1 到 i 的最短路长度。不能到达输出 1-1

Sample Input

5
1 5 6 7 8

Sample Output

0 6 17 8 -1

HINT

对于 100 %100 \ \% 的数据, 1n105,0ai2301≤n≤10^5, 0≤a_i​≤2^{30}

解题思路

本题关键在于建图,对于 1n1-n 看作 nn 个节点,此外由于 0ai2300≤a_i​≤2^{30},所以 aia_i 在二进制下最多有 3131 位,看作 3131 个节点,若 aia_i 二进制值的第 jj 位是 11 ,则对 aia_ijj 建边,边权为 aia_i ,然后跑一次最短路即可。 PS:注意边的数量要开够

AC codeAC \ code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 99;

inline int read()
{
    char c = getchar();
    int x = 0;
    bool f = 0;
    for (; !isdigit(c); c = getchar())
    {
        f ^= !(c ^ 45);
    }
    for (; isdigit(c); c = getchar())
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
    }
    if (f)
    {
        x = -x;
    }
    return x;
}

inline void write(int x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x > 9)
    {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}

long long n, m;
array<long long, maxn> dis;
bool vis[maxn];
long long x[maxn];

struct edge
{
    int to, w;
};
vector<edge> d[maxn];

struct node
{
    long long i, dis;
    bool operator<(const node tmp) const
    {
        return tmp.dis < dis;
    }
};

void add(int a, int b, int w)
{
    d[a].push_back({b, w});
}

void Dijkstra()
{
    dis.fill(0x3f3f3f3f3f);
    priority_queue<node> q;
    dis[1] = 0;
    q.push({1, 0});
    while (!q.empty())
    {
        node tmp = q.top();
        q.pop();
        int t = tmp.i;
        if (vis[t])
            continue;
        vis[t] = 1;
        for (int i = 0; i < d[t].size(); i++)
        {
            if (dis[t] + d[t][i].w < dis[d[t][i].to])
            {
                dis[d[t][i].to] = dis[t] + d[t][i].w;
                q.push({d[t][i].to, dis[d[t][i].to]});
            }
        }
    }
}

signed main()
{
    n = read();
    for (int i = 1; i <= n; ++i)
    {
        x[i] = read();
        for (int j = 0; j <= 30; j++)
            if ((x[i] & (1 << j)) != 0)
                add(i, n + j + 1, x[i]), add(n + j + 1, i, x[i]);
    }
    Dijkstra();
    for (int i = 1; i <= n; ++i)
    {
        write((dis[i] == 0x3f3f3f3f3f ? -1 : dis[i]));
        putchar(' ');
    }
    return 0;
}
posted @ 2021-06-22 21:52  蒟蒻orz  阅读(4)  评论(0编辑  收藏  举报  来源