(构造题)
题意:
给你一棵树,要求构造这样一个序列,当节点i与节点j连边,需要满足a[i]|a[j]=2^60-1
节点个数小于100
思考过程:
通过画一个链来观察不难发现,x - y - z… 其中至少有一位x,z是一定不一样的
看到这个构造题我们是很想给每个节点对应一个位的,假设一种更易构造的条件,a[i]|a[j]=2^200-1,那么可以给每个节点对应一个位,考虑到i与j的连接条件,我们先使节点i的第i位为0,其余位为1,同时我们可以将树黑白染色掉,使同色的点有一位为0,那么同色的点一定不会相连,接下来考虑怎么样使不同色的点可以相连或者不相连,若保持一种颜色的点仍然为 节点i的第i位为0,其余位为1,那么与其相连的不同色的点j至少应满足第i位为1,那么我们可以贪心地想到,使这个节点j除了保持连不同色的点的位为1,同色点统一为0的位为0外(可能有点绕,就是上述的黑白染色),只有j与一个点i相连,我们才使j的第i位为0,此时由于不连i的点j的第i位由于一定不为1,所以a[i]|a[j]=2^200-1的条件一定不成立。
至此,对于a[i] | a[j]=2^200 -1 的构造条件我们完成了。考虑怎样压缩,显然不同色的点可以分开编号,且一定有一种色的点数小于n/2,那么我们以这种点为上述的点i,即可完成a[i]|a[j]=2^p-1, 2*p>n的情况下构造。
#include<bits/stdc++.h>
using namespace std;
const int N=110;
typedef long long ll;
bool g[N][N];
vector<int> v[2];
int n;
ll w[N];
int pl[N];
void dfs(int x,int fa,int c){
v[c].push_back(x);
for(int i=1;i<=n;i++){
if(i==x||i==fa) continue;
if(g[x][i]) dfs(i,x,1-c);
}
}
int main(){
cin>>n;
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
g[x][y]=g[y][x]=1;
}
dfs(1,0,0);
if(v[0].size()>v[1].size()) swap(v[0],v[1]);
for(int i=0;i<v[0].size();i++){
int x=v[0][i];
pl[x]=i;
w[x]=(1L<<59)-1-(1L<<i);
}
for(int i=0;i<v[1].size();i++){
int x=v[1][i];
w[x]=(1L<<59);
for(int j=1;j<=n;j++){
if(g[x][j]) w[x]+=(1L<<pl[j]);
}
}
for(int i=1;i<=n;i++) cout<<w[i]<<" ";
}