F - Encounter and Farewell
观摩自大佬博客 https://blog.csdn.net/qq_42101694/article/details/116349687
只写关于其中一些不懂的解释
关于这个a-b的路径为何能用补集中的数异或出来呢。
假设有三条边,联通的。a - b - c ,那么a ^ c=a ^ b ^ b ^ c,其中a ^ b,b ^ c分别是边权。也就是a ^ c等于路径异或值,也就是可以被补集中的一些数字异或得到。
充要条件为什么会是这个呢。我们可以把构造出的一个树看出以0为根节点的树,0 ^ i = i ,所以被异或出来的和要有所有的0-i这个路径,必须要有全部的。
然后怎么构造,直接用并查集暴力就行了,线性基里面最多只有18个。
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3 , "Ofast" , "inline")
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization("unroll-loops")
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#include <bitset>
#include <deque>
using namespace std ;
#define ios ios::sync_with_stdio(false) , cin.tie(0)
#define x first
#define y second
#define pb push_back
#define ls rt << 1
#define rs rt << 1 | 1
typedef long long ll ;
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
int n , a[N] , b[N] , id[N] , fa[N] ;
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]) ;
}
int nn , m ;
int work()
{
cin >> nn >> m ;
for(int i = 0 ;i <= 18 ;i ++ )
if(nn >> i & 1) n = i ;
for(int i = 0 , x ; i < m ;i ++ ) cin >> x , a[x] = 1 ;
for(int i = 1 ;i < nn ;i ++ ) {
if(!a[i]) {
int x = i ;
for(int j = n ;j >= 0 ;j -- ) {
if(x >> j & 1) {
if(b[j]) x ^= b[j] ;
else {
b[j] = x ;
id[j] = i ;
break ;
}
}
}
}
}
for(int i = 0 ;i < n ;i ++ )
if(!id[i]) return 0 * puts("-1") ;
for(int i = 0 ;i < nn ;i ++ ) fa[i] = i ;
for(int i = 0 ;i < nn ;i ++ )
for(int j = 0 ;j < n ;j ++ ) {
int fu = find(i) , fv = find(i ^ id[j]) ;
if(fu != fv) {
cout << i << " " << (i ^ id[j]) << "\n" ;
fa[fu] = fv ;
}
}
return 0 ;
}
int main()
{
// freopen("C://Users//spnooyseed//Desktop//in.txt" , "r" , stdin) ;
// freopen("C://Users//spnooyseed//Desktop//out.txt" , "w" , stdout) ;
work() ;
return 0 ;
}
/*
*/
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。