Codeforces Round 782 (Div. 2) E. AND-MEX Walk(思维+并查集)

news/2024/7/15 18:54:08 标签: 算法, c++, 数据结构, 深度优先, 图论

原题链接:E. AND-MEX Walk


题目大意:


给出一张 n n n 个点 m m m 条边的无向图,边带有边权。

我们定义一条路径的价值为:

假设我们经过了 k k k 个点(点和边都可重复经过),且按顺序经过的边的权值分别为 { w 1 , w 2 , w 3 , . . . , w k − 1 } \{w_1,w_2,w_3,...,w_{k-1}\} {w1,w2,w3,...,wk1} ,那么 m e x { w 1 , w 1 & w 2 , . . . , w 1 & w 2 & . . . & w k − 1 } mex\{w_{1},w_{1}\&w_{2},...,w_{1}\&w_{2}\&...\&w_{k-1}\} mex{w1,w1&w2,...,w1&w2&...&wk1} 就是我们路径的价值。( 其中 & \& & 为二进制的与的操作, m e x { S } mex\{S\} mex{S} 为集合 S S S 中没有出现过的最小的自然数)。

现在给出 q q q 次询问,每次给出两个不同的点 u , v u,v u,v ,问你从 u u u 出发经历一些点到达点 v v v 所能获得的路径的价值的最小值为多少。

解题思路:


答案只会出现 0 , 1 , 2 0,1,2 0,1,2 三种情况,感性证明一下:

假设要使得我们的 m e x { S } ≥ 3 mex\{S\}\geq3 mex{S}3 ,那么就要让我们的 S = { 0 , 1 , 2 } S=\{0,1,2\} S={0,1,2} 在我们的序列中全都出现过。

假设我们经历了一系列前缀与的情况,最后剩下一个 2 2 2 ,现在我们还要走过一系列的点,然后使得 1 1 1 出现在我们的序列中(或者剩下一个 1 1 1,再使得 2 2 2 出现)。

但注意到 2 = ( 10 ) 2 , 1 = ( 01 ) 2 2=(10)_{2},1=(01)_{2} 2=(10)2,1=(01)2,它们相互与起来为 0 = ( 00 ) 2 0=(00)_{2} 0=(00)2 ,那么想要使得 1 , 2 1,2 1,2 都同时出现在 m e x { S } mex\{S\} mex{S} 序列中同时出现,由于有 与运算 这个操作在,两者必然不可能同时出现。

对于上面所讨论的情况而言,我们最后一定只会只有 { 1 , 0 } , { 2 , 0 } , \{1,0\},\{2,0\}, {1,0},{2,0}, ,即答案一定会被限制在 { 0 , 1 , 2 } \{0,1,2\} {0,1,2} 中。

想想怎么做:

先考虑 m e x { S } = 0 mex\{S\}=0 mex{S}=0 的情况,对于这种情况来说,我们的 与操作 只要保证选出一些边,且某个二进制位上一直包含有 1 1 1 ,且这些边使得我们 u → v u \rightarrow v uv 联通即可,比较简单的一个想法就是,对每个二进制位开一个并查集,然后直接判连通性即可。

再考虑 m e x { S } = 1 mex\{S\}=1 mex{S}=1 的情况,假设我们 u → v u \rightarrow v uv与操作 不能使得某个二进制位上一直包含有 1 1 1 ,即我们 u , v u,v u,v 不在一个第 i i i 个二进制位的并查集之内( 没有任何一个 2 i 2^{i} 2i 位在路径上是一直出现的 ),那么这一定会使得我们 0 0 0 出现在 S S S 当中,因为此时我们必定要选出一条不包含 2 i 2^{i} 2i 的边( 否则 u u u 无法走到 v v v ),然后走过这条边。

那么什么时候会出现 1 1 1 呢?

给出一个结论:按上面的来说,我们与序列一定是 S = { a , b , c , d , . . . , 0 , 0 , 0 , 0 , . . . } S=\{a,b,c,d,...,0,0,0,0,...\} S={a,b,c,d,...,0,0,0,0,...}只要我们能使得那些二进制第 2 0 2^{0} 20 位不 单独出现 a , b , c , d , . . . , 0 a,b,c,d,...,0 a,b,c,d,...,0 这一段之间即可,怎么保证?我们只需要有至少存在某个二进制位 2 i ( i ≠ 0 ) 2^{i}(i\neq0) 2i(i=0) 和它一起同时出现,或者 2 0 2^{0} 20 不出现即可。那么我们最开始先保留二进制 2 i 2^{i} 2i 位,在此基础上我们任选一条边与起来,使得 2 0 2^{0} 20 这一位变成 0 0 0 ,最后再走任意的 ( u → v ) (u \rightarrow v) (uv) 的路径使得 m e x { S } = 0 mex\{S\}=0 mex{S}=0 即可。

可知这样做,我们最开始由于存在 2 i 2^{i} 2i 不会出现单独的 2 0 2^{0} 20,我们最后将 2 i 2^{i} 2i 消掉时,我们也能保证 2 0 2^{0} 20 在最开始时被消掉了,故 2 0 2^{0} 20 不可能单独出现。

要这样做,我们要找出所有能让 2 0 2^{0} 20 位为 0 0 0 的边,再找一个含有 2 i ( i ≠ 0 ) 2^{i}(i\neq0) 2i(i=0) 的并查集,和这些边合并起来,再判断 u , v u,v u,v 是否在这些新的并查集中即可。

再考虑 m e x { S } = 2 mex\{S\}=2 mex{S}=2 的情况,显然答案只会有 0 , 1 , 2 0,1,2 0,1,2 ,只要上面的情况不满足,那么我们的答案就一定会是 2 2 2 了。

时间复杂度: O ( n log ⁡ w + ( m + q ) α ( n ) log ⁡ w ) O(n\log w+(m+q)\alpha(n)\log w) O(nlogw+(m+q)α(n)logw)

AC代码:

#include <bits/stdc++.h>
using namespace std;

using PII = pair<int, int>;
using i64 = long long;

struct DSU {
    vector<int> fa, siz;
    DSU(int n) : fa(n + 1), siz(n + 1, 1) { iota(fa.begin(), fa.end(), 0); };
    int find(int x) {
        while (x != fa[x]) x = fa[x] = fa[fa[x]];
        return x;
    }
    int size(int x) { return siz[find(x)]; }
    bool same(int x, int y) { return find(x) == find(y); }
    bool merge(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) return false;
        siz[y] += siz[x];
        fa[x] = y;
        return true;
    }
};

void solve() {
    int n, m;
    cin >> n >> m;

    vector dsu1(31, DSU(n));

    vector<bool> mark(n + 1);
    for (int i = 1; i <= m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        for (int j = 0; j <= 30; ++j) {
        	//至少包含 2^i 的并查集
            if (w >> j & 1) {
                dsu1[j].merge(u, v);
            }
        }
        if (~w & 1) {
            mark[u] = mark[v] = true;
        }
    }

    auto dsu2 = dsu1;//判1的并查集
    for (int j = 0; j <= 30; ++j) {
        for (int i = 1; i <= n; ++i) {
        	//将至少包含 2^i 的并查集和 2^0 = 0 的边并起来 保证最后 2^0 恒为0
            if (mark[i]) {
                dsu2[j].merge(i, 0);
            }
        }
    }

    int q;
    cin >> q;

    for (int i = 1; i <= q; ++i) {
        int u, v;
        cin >> u >> v;

        int ans = 2;//先设为2
        for (int j = 0; j <= 30; ++j) {
	        //是否可以为0
            if (dsu1[j].same(u, v)) {
                ans = min(ans, 0);
            }
        }

        for (int j = 1; j <= 30; ++j) {
        	//是否可以为1
            if (dsu2[j].same(u, 0)) {
                ans = min(ans, 1);
            }
        }
		//否则为2
        cout << ans << '\n';
    }
}

signed main() {

    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int t = 1; //cin >> t;
    while (t--) solve();

    return 0;
}

http://www.niftyadmin.cn/n/5402212.html

相关文章

UCSF DOCK 分子对接详细案例(01)- rigid, fixed anchor, flexible dock

欢迎浏览我的CSND博客&#xff01; Blockbuater_drug …点击进入 文章目录 前言一、操作环境二、研究背景三、受体-配体结构文件准备3.1准备文件夹DOCK_workdir, 下载晶体结构3.1.1 来自湿实验的受体配体共晶结构&#xff1a;3.1.2 来自深度学习和语言模型推理预测的蛋白结构&a…

【多线程】CAS详解

目录 &#x1f334;什么是 CAS&#x1f338;CAS 伪代码 &#x1f38d;CAS 是怎么实现的&#x1f340;CAS 有哪些应⽤&#x1f338;实现原子类&#x1f338;实现自旋锁 &#x1f333;CAS 的 ABA 问题&#x1f338;**什么是 ABA 问题**&#xff1f;&#x1f338;ABA 问题引来的 B…

JVM 第四部分—垃圾回收概念 和 算法 1

垃圾回收概述 什么是垃圾&#xff1f; 垃圾指的是运行程序中没有任何指针指向的对象&#xff0c;这个对象就是需要被回收的垃圾垃圾回收不是Java的伴生产物&#xff0c;早在1960年&#xff0c;第一门使用动态内存分配和垃圾回收的Lisp语言就诞生了 为什么需要GC&#xff1f; 1…

selenium for java 基本使用

selenium 使用 maven <!-- seleium --><properties><selenium.version>4.18.1</selenium.version></properties><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId>…

Bun 单元测试实践

当前要测试 index.js 文件中 requestProductList 方法&#xff0c;requestProductList 方法中引入了 utils.js 文件中的 getProductList 方法&#xff0c;getProductList 方法返回异步网络请求的数据。 index.js import { getProductList } from ./utils;/*** 获取产品列表* …

vue实现水印功能

目录 一、应用场景 二、实现原理 三、详细开发 1.水印的实现方式 2.防止用户通过控制台修改样式去除水印效果&#xff08;可跳过&#xff0c;有弊端&#xff09; 3.水印的使用 &#xff08;1&#xff09;单页面/全局使用 &#xff08;2&#xff09;全局使用个别页面去掉…

智能驾驶规划控制理论学习02-基于搜索的路径规划方法

目录 一、路径搜索问题 二、图论基础 三、图搜索方法 1、广度优先搜索&#xff08;BFS&#xff09; bfs与dfs的区别 bfs的搜索过程 bfs的算法实现 2、迪杰斯特拉算法&#xff08;Dijkstra&#xff09; 核心思想 优先级队列 Dijkstra搜索过程 Dijkstra优缺点…

Unity 游戏设计模式:观察者模式

本文由 简悦 SimpRead 转码&#xff0c; 原文地址 mp.weixin.qq.com 在 unity 游戏设计中&#xff0c;观察者模式&#xff08;Observer Pattern&#xff09;有着重要的作用&#xff0c;它主要用于实现对象之间的一对多的依赖关系&#xff0c;当一个对象的状态发生变化时&#x…