J.Tree Constructer (2021 icpc 济南)

题意

给定一棵树 假设两个点or值为 2^60-1 则这两个点会连一条边 问实现这棵树的话每个点的值为多少

思路

二分图 + 构造 先把所有点分成两份 每个集合内部不会连边 然后给这两个集合赋值 使得两个集合中连边的两点or值为2^60-1
记录一下哪个集合的点最少 然后给这个集合的每个点赋个序号 假设分为黑点白点 黑点最少 我们可以使黑点每位全赋值为1(除了最高位) 然后把它的序号位改为0(防止连到其他点) 而对于白点 我们可以全赋值为0最高位为1然后将它所连的两个点的序号位改为1

代码

#include 

using namespace std;

typedef long long ll;

const int N = 110;

int n;
int dep[N], fa[N], cnt[N];
ll ans[N];
bool flag = true;
int id;

vector<int> G[N];

void dfs(int u, int father, int depth)
{
    dep[u] = depth;
    if (dep[u] & 1) cnt[1] ++ ;
    else cnt[0] ++ ;
    for (int i = 0; i < G[u].size(); i ++ )
    {
        int to = G[u][i];
        if (to == father) continue;
        dfs(to, u, depth + 1);
    }
}

int main()
{
    cin >> n; id = 1;
    for (int i = 1; i < n; i ++ )
    {
        ll u, v;
        scanf("%lld%lld", &u, &v);
        G[u].push_back(v); G[v].push_back(u);
    }
    dfs(1, 0, 1);
    
    if (cnt[1] >= cnt[0]) flag = true;
    else flag = false;
   
    for (int i = 1; i <= n; i ++ )
    {
        if (dep[i] % 2)
        {
            if (flag) dep[i] = 0;
            else dep[i] = id ++ ;
        }
        else 
        {
            if (flag) dep[i] = id ++ ;
            else dep[i] = 0;
        }
    }    
    
    for (int i = 1; i <= n; i ++ )
    {
        if (dep[i] == 0)
        {
            ans[i] = (1ll << 59);
            for (int j = 0; j < G[i].size(); j ++ )
                ans[i] += (1ll << dep[G[i][j]]);
        }
        else 
        {
            ans[i] = (1ll << 60) - 1;
            ans[i] -= (1ll << 59);
            ans[i] -= (1ll << dep[i]);
        }
        cout << ans[i] << " ";
    }
    
    return 0;
}

你可能感兴趣的:(c语言)