题目描述
现在给定描述,如果两个点之间的或运算结果答案是,说明这两个点之间有边。
问给你一个n个节点,你如何设置节点值,使得构造出来的图是一棵树,题目给出数的边信息。
,输出构造的节点值。
Solution
数据范围的n很小,并且答案给的是一个关于的幂次的形式,那么就要往二进制方向靠。
这也是一个比较新奇的思维题了吧,如果当时脑子没想明白可能很难写出来,想明白了或者见过类似的就会很容易。
我们首先根据题目给出的树边信息,进行二分图的黑白染色。把树中全部节点分为黑白两种节点。
那么我们在假设白节点数小于黑节点数的前提下。进行下面的分配操作。
对全部的白色节点进行编号,使得这些白色节点的权值二进制表示中它的编号位是,以及最高位也就是位是。
全部黑色节点,只把它的二进制表示位第位置为,其余的,和它相邻的白点编号的二进制对应位置都置为。
进行上面操作之后你就得到了答案。现在我们想想为什么这样就会符合要求。
第一步我们先看对白色节点的分配操作,全部的白色节点最高位也就是位都不是,以及对应编号位也不是,说明任意两个白色节点之间都不会存在边。
第二步我们看黑色节点的分配操作,它把最高位设置成了,也把和它相邻的编号位都设置成了,这样说明和它相邻的白点都有到对应的边,不和它相邻的白点,因为编号不一致,导致二进制位不同为,一定不会有和它连边的情况。
第三步我们看为什么要使得白色节点数小于黑色节点数。如果不考虑先白还是先黑染色,很容易构造出一个菊花图,假设第一个节点是黑的,那么它的全部孩子都是白的,最多有个白节点,但是我最高的二进制位只有并且还不能标编号,所以我们最多只能支持有个白色编号,因为数的结构特性,我们一定有一种颜色是小于的,那么只要找到染色方案,使得白色数量不要超过即可。并且这里也解释了为什么黑点之间一定不会有边,如果我们要让黑点之间存在一条边,说明一定有两个黑点他们链接的白点之间数量大于个,才可能存在一条边,但是这样的黑点存在吗,看看我们上面使得白节点数一定小于黑节点数这个要求,如果白节点有了个,在最多个节点的树中,这是不存在的情况。所以这个问题也就得到了解决。
这个思维题关键在于转换二分染色,以及边权关系如何处理,还要保证某个特定的颜色满足一定的需求,例用题目给出的数据范围,确定我们的做法是正确的。)当然确定正确这个东西如果在赛场上,如果没什么好的别的想法就先一发再说,指不定就了呢。
#include <bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) #define all(__vv__) (__vv__).begin(), (__vv__).end() #define endl "\n" #define pai pair<int, int> #define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__)) #define rep(i, sta, en) for(int i=sta; i<=en; ++i) typedef long long ll; typedef unsigned long long ull; typedef long double ld; inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; } inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op) putchar(op); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); if (op) putchar(op); } inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; } const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; const int N = 100 + 7; ll n, m; int head[N], tot; struct Node { int v, nxt; }edge[N << 1]; void add(int u, int v) { edge[++tot].v = v; edge[tot].nxt = head[u]; head[u] = tot; } int id[N]; ll ans[N]; vector<int> color[2]; void dfs(int u, int fa, int col) { // 黑白染色 color[col].push_back(u); for (int i = head[u]; i; i = edge[i].nxt) { int v = edge[i].v; if (v == fa) continue; dfs(v, u, col ^ 1); } } void solve() { n = read(); rep(i, 1, n - 1) { int u = read(), v = read(); add(u, v), add(v, u); } dfs(1, -1, 0); if (color[0].size() > color[1].size()) swap(color[0], color[1]); // 白点选择少的哪一些 int cnt = 0; ll bs[70]; rep(i, 0, 62) bs[i] = 1ll << i; // 写一堆位运算比较麻烦 for (auto& it : color[0]) { // 白点 ans[it] = bs[60] - 1 - bs[59] - bs[cnt]; id[it] = cnt++; } for (auto& it : color[1]) { // 黑点 ll tmp = 0; for (int i = head[it]; i; i = edge[i].nxt) { int v = edge[i].v; tmp |= bs[id[v]]; } ans[it] = bs[59] + tmp; } rep(i, 1, n) print(ans[i], 32); } int main() { //int T = read(); while (T--) solve(); return 0; }