F

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]) << "
" ;
  	 		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 ;
}
/*

*/

每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
原文地址:https://www.cnblogs.com/spnooyseed/p/14819407.html