Tree Constructer 构造 + 二分图 济南 ICPC 2020

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;
}
原文地址:https://www.cnblogs.com/EchoZQN/p/14401998.html