也就是说,我们贪心的来想,肯定是先要让相同值的元素先建边,然后再是选择lowbit(x) == 1的,然后再是2的,再是4的以此类推,那么贪心的思维就出来了。
然后咋一看,是
的做法啊!怎么优化?我们肯定是要0和1进行合并的,每一位的0、1进行合并,是为了贪心的考虑,所以说,我们从并查集的角度来看,不妨先是0中的第一个元素去合并完1中的所有元素,然后保留一个1中的元素,继续,把0后面的所有元素去看能不能和1中的这一个元素进行合并来是的复杂度变成
。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e5 + 7;
int N, root[maxN];
int fid(int x) { return x == root[x] ? x : root[x] = fid(root[x]); }
deque<int> vt[30][2];
map<int, int> mp;
int main()
{
scanf("%d", &N);
for(int i=1; i<=N; i++) root[i] = i;
int line = 0;
ll ans = 0;
for(int i=1, val, id, fu, fv; i<=N; i++)
{
scanf("%d", &val);
if(mp[val])
{
fu = fid(mp[val]); fv = fid(i);
if(fu ^ fv) { line++; root[fu] = fv; }
continue;
}
mp[val] = i;
for(int j=0; j<30; j++)
{
id = val & 1;
vt[j][id].push_back(i);
val >>= 1;
}
}
for(int i=0, fu, fv; i<30; i++)
{
if(line == N - 1) break;
for(auto it=vt[i][0].begin(); it != vt[i][0].end(); it++)
{
fu = fid(*it);
while(!vt[i][1].empty() && (vt[i][1].size() ^ 1))
{
fv = fid(vt[i][1].front());
vt[i][1].pop_front();
if(fu ^ fv) { line ++; root[fu] = fv; ans += 1LL << (ll)i; }
}
if(!vt[i][1].empty())
{
fv = fid(vt[i][1].front());
if(fu ^ fv) { line ++; root[fu] = fv; ans += 1LL << (ll)i; }
}
if(line == N - 1) break;
}
}
printf("%lld\n", ans);
return 0;
}
来源:CSDN
作者:Andres_Lionel
链接:https://blog.csdn.net/qq_41730082/article/details/104201020