[ICPC2020济南J] Tree Constructer - 构造
Description
给定一棵树,让你给节点赋值,要求相连的两个点的值进行或操作后结果为 (2^{60}-1)
Solution
我们要将所有点分成两部分,使得边都在两部分之间,我们可以通过双标志位来使得两个部分内部互相不连边
现在只要搞定两部分之间的连边就可以了
我们对较少的那部分,每个点分配一个独立的编号 (1,2,3,4,...),除了标志位(放在高位)外,其余的都打成 (1),只有编号对应的位打成 (0),类似 (0111 1110, 0111 1101, ...) 这样
对于较多的那部分,尽可能让更多的位是 (0),而它相邻的少点,对应编号位设为 (1),这样就能保证,只与相邻的少点连边(因为少点空成 (0) 的地方它都填 (1) 了),而不与其它少点相连
考虑怎么写得简单一点,我们开一堆长度为 60 的 bitset,最后转成 ulong 即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 205;
int n, c[N];
bitset<60> a[N];
vector<int> g[N];
void dfs(int p, int from)
{
for (int q : g[p])
{
if (q != from)
{
c[q] = 1 - c[p];
dfs(q, p);
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i < n; i++)
{
int t1, t2;
cin >> t1 >> t2;
g[t1].push_back(t2);
g[t2].push_back(t1);
}
dfs(1, 0);
int cnt[2] = {0, 0};
for (int i = 1; i <= n; i++)
cnt[c[i]]++;
if (cnt[0] > cnt[1])
{
for (int i = 1; i <= n; i++)
c[i] = 1 - c[i];
}
int ind = 0;
map<int, int> mp;
for (int i = 1; i <= n; i++)
if (c[i] == 0)
{
a[i][59] = 0;
a[i][58] = 1;
for (int j = 57; j >= 0; j--)
a[i][j] = 1;
a[i][ind++] = 0;
mp[i] = ind - 1;
}
for (int i = 1; i <= n; i++)
if (c[i] == 1)
{
a[i][59] = 1;
a[i][58] = 0;
for (int j = 57; j >= 0; j--)
a[i][j] = 0;
for (auto q : g[i])
a[i][mp[q]] = 1;
}
for (int i = 1; i <= n; i++)
{
int tmp = 0;
for (int j = 0; j < 60; j++)
if (a[i][j])
tmp |= 1ll << j;
cout << tmp << " ";
}
}