题意
有n个点的图中,满足如果两个点的权值或运算之后等于260 -1,则两点之间可以连边。题中会给n-1条边,问每个点权应该是多少。
分析
由于n的范围非常小,可以直接考虑每一位上的构造。
我们采用如上构造方式,我们先给每个节点编号,但要保证白色为个数少的那个,从而确保60位上可以任意选择。
- 对于白色的点,我们先将最高位置0,在让第id位也置0,其余为1,这样可以保证所有白色点之间不会有边
- 对于所有黑的的点,我们先将最高位置1,再与它相邻的所有点的第id位置1,其余为0,从而确保与所有相邻的白色节点都满足条件。
Code
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 200, M = 5e5 + 10, INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
vector<int> vec[2], g[N];
int n, id[N];
ll ans[N];
void dfs(int x, int fa, int color) {
vec[color].push_back(x);
for (auto v : g[x]) {
if (v == fa) continue;
dfs(v, x, color^1);
}
}
void solve() {
cin >> n;
for (int i = 1; i <= n-1; i++) {
int u, v; cin >> u >> v;
g[u].push_back(v), g[v].push_back(u);
}
dfs(1, 0, 1);
if (vec[0].size() > vec[1].size()) swap(vec[0], vec[1]);
for (int i = 0; i < vec[0].size(); i++) {
ans[vec[0][i]] = (1ll << 60) - 1 - (1ll << i) - (1ll << 59);
id[vec[0][i]] = i;
}
for (int i = 0; i < vec[1].size(); i++) {
id[vec[1][i]] = i;
ll tmp = (1ll<<59);
for (auto v : g[vec[1][i]]) {
tmp += (1ll << id[v]);
}
ans[vec[1][i]] = tmp;
}
for (int i = 1; i <= n; i++) printf("%lld ", ans[i]);
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("Test/input", "r", stdin);
freopen("Test/output", "w", stdout);
#endif
solve();
return 0;
}
赛中最后想到构造方法但没注意到一些细节就一直没过,一定要确定一个小的块!!!