45届ICPC济南站J-Tree Constructer二分图构造

(构造题)

题意:

给你一棵树,要求构造这样一个序列,当节点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]<<" ";
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值