Tree Constructer 构造 + 二分图
题目大意:
给你一棵树,让你去重新赋予每一个节点一个权值,如果节点 ((u,v)) 连边,那么 ((a_u \,or\,a_v )= 2^{60}-1) ,反之也成立,问你如何进行赋值,保证最后连成的树是题目所给定的。
题解:
比赛的时候,想的很慌乱,没有想到树本来就是一个二分图。
- 树是一个二分图,那么变成两个点集,因为树最多只有100个节点,那么这个点集里面肯定有一个的节点数量小于等于50
- 所以我就取点集小的设为 A,另一个设为B,因为要求等于 (2^{60}-1) ,那么就一共有60位可以分配,首先保证两个点集内部不想连,所以最高位分配,A最高位为0,B最高位为1。
- 接下来就主要操作A点集,A点集的每一个数我都给它分配一位,如果A点集有 (x) 位,那么就分配了 (x) 位了,就相当于A点集每个节点是一把锁,每一位就是一把不同的锁,B点集就是钥匙,它和谁连就需要谁的钥匙,那位就置为1,其他不需要的就置为0
非常有趣的一个构造,可惜没有想出来。。。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 2e2+10;
vector<int>G[maxn];
void add(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
int dep[maxn],num[2];
void dfs(int u,int pre,int d){
dep[u] = d,num[d&1]++;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(v == pre) continue;
dfs(v,u,d+1);
}
}
ll bit[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
}
dfs(1,0,1);
int x = 0;
if(num[1]<num[x]) x = 1;
ll S = 1ll<<59,now = 1;
for(int i=1;i<=n;i++){
if((dep[i]&1)==x){
bit[i] = (S - 1)^now;
now = now*2;
}
}
for(int i=1;i<=n;i++){
if((dep[i]&1)!=x){
bit[i] = S;
for(int j=0;j<G[i].size();j++){
int v = G[i][j];
bit[i] |= bit[v]^(S-1);
}
}
}
for(int i=1;i<=n;i++) {
printf("%lld",bit[i]);
if(i==n) printf("
");
else printf(" ");
}
return 0;
}