[ICPC2020济南J] Tree Constructer

[ICPC2020济南J] Tree Constructer - 构造

Description

给定一棵树,让你给节点赋值,要求相连的两个点的值进行或操作后结果为 (2^{60}-1)

Solution

我们要将所有点分成两部分,使得边都在两部分之间,我们可以通过双标志位来使得两个部分内部互相不连边

现在只要搞定两部分之间的连边就可以了

我们对较少的那部分,每个点分配一个独立的编号 (1,2,3,4,...),除了标志位(放在高位)外,其余的都打成 (1),只有编号对应的位打成 (0),类似 (0111 1110, 0111 1101, ...) 这样

对于较多的那部分,尽可能让更多的位是 (0),而它相邻的少点,对应编号位设为 (1),这样就能保证,只与相邻的少点连边(因为少点空成 (0) 的地方它都填 (1) 了),而不与其它少点相连

考虑怎么写得简单一点,我们开一堆长度为 60 的 bitset,最后转成 ulong 即可

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 205;

int n, c[N];
bitset<60> a[N];
vector<int> g[N];

void dfs(int p, int from)
{
    for (int q : g[p])
    {
        if (q != from)
        {
            c[q] = 1 - c[p];
            dfs(q, p);
        }
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i < n; i++)
    {
        int t1, t2;
        cin >> t1 >> t2;
        g[t1].push_back(t2);
        g[t2].push_back(t1);
    }
    dfs(1, 0);

    int cnt[2] = {0, 0};
    for (int i = 1; i <= n; i++)
        cnt[c[i]]++;
    if (cnt[0] > cnt[1])
    {
        for (int i = 1; i <= n; i++)
            c[i] = 1 - c[i];
    }
    int ind = 0;
    map<int, int> mp;
    for (int i = 1; i <= n; i++)
        if (c[i] == 0)
        {
            a[i][59] = 0;
            a[i][58] = 1;
            for (int j = 57; j >= 0; j--)
                a[i][j] = 1;
            a[i][ind++] = 0;
            mp[i] = ind - 1;
        }
    for (int i = 1; i <= n; i++)
        if (c[i] == 1)
        {
            a[i][59] = 1;
            a[i][58] = 0;
            for (int j = 57; j >= 0; j--)
                a[i][j] = 0;
            for (auto q : g[i])
                a[i][mp[q]] = 1;
        }
    for (int i = 1; i <= n; i++)
    {
        int tmp = 0;
        for (int j = 0; j < 60; j++)
            if (a[i][j])
                tmp |= 1ll << j;
        cout << tmp << " ";
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/14563246.html