Atcoder Beginner 245 G

G - Foreign Friends

题意:给出一个带边权的无向图,每个点有一个颜色,其中还有若干个特殊点。现在要求输出:每个点前往一个颜色与自己不同的特殊点的最短距离

解法:首先不考虑颜色,这个题就是一个魔改的dij,初始将所有特殊点加入队列跑一遍即可。

然后我们考虑颜色,可以将颜色按照二进制位拆开,枚举每一位,将所有在这一位上为0的特殊点加入队列跑一遍dij,并且更新在这一位上为1的点的答案。同样反过来也这么搞一遍

两个颜色不同,则它们至少有一位二进制是不同的(废话

所以任意点距离不同颜色的特殊点之间的最短路一定会被算到。

复杂度 \(O(logn*dij)\)

int n, m, K, L;
int a[maxn], b[maxn];

struct node{
    int t;
    ll dis;
    node(int x, ll y): t(x), dis(y){}
    bool operator >(const node &p)const{
        return dis > p.dis;
    }
};
vector<node> vp[maxn];

ll dis[maxn], ans[maxn];
void dij(int k, int x){
    priority_queue<node, vector<node>, greater<node> > q;
    fill(dis, dis+n+1, 1e18);
    for(int i=0;i<L;i++){
        if((a[b[i]] >> k & 1) == x){
            q.push({b[i], 0});
            dis[b[i]] = 0;
        }
    }
    while(!q.empty()){
        node u = q.top();
        q.pop();
        if(dis[u.t] < u.dis) continue;
        if((a[u.t] >> k & 1) == (x^1)) ans[u.t] = min(ans[u.t], dis[u.t]);
        for(node e: vp[u.t]){
            int v = e.t;
            if(dis[v] > dis[u.t] + e.dis){
                dis[v] = dis[u.t] + e.dis;
                q.emplace(v, dis[v]);
            }
        }
    }
}

void solve(){
    cin >> n >> m >> K >> L;
    for(int i=1;i<=n;i++) cin >> a[i];
    for(int i=0;i<L;i++) cin >> b[i];
    for(int i=1;i<=m;i++){
        int u, v, d;
        cin >> u >> v >> d;
        vp[u].emplace_back(v, d);
        vp[v].emplace_back(u, d);
    }
    fill(ans, ans+n+1, 1e18);
    for(int k=17;k>=0;k--){
        dij(k, 0);
        dij(k, 1);
    }
    for(int i=1;i<=n;i++) cout << (ans[i] > (ll)1e17 ? -1 : ans[i]) << " \n"[i == n];
}

Atcoder Beginner 245 G
http://www.lxtyin.ac.cn/2022/03/31/题解/Atcoder ABC 245 G/
作者
lx_tyin
发布于
2022年3月31日
许可协议