[2020ICPC济南] Tree Constructer

链接

Tree Constructer

思路

题意是这样的:给一个可重集,其中任意两个元素的或和(即 x | y)若为 \(2^{60}-1\) 则在它们之间连一条无向边。给出一棵树,让你构造一个集合使其对应的图就是这棵树。

稍微模拟几种情况可以发现,同一层的点存在某种关系,相邻两层的点之间也存在某种关系,而树又必然是二分图,可以利用二分图的性质去构造。

先 DFS 一遍给所有点分类,选择点数不大于一半的一边为左边,然后用两位来标识:左边都是 01 右边都是 10,这样同一边的点之间就连不上边。对于左边的点,按顺序将其对应的那一位的 1 去掉,只有和他相连的右边的点这一位才取 1。由于之前左边的点数不超过一半,这里最多需要 \(50\) 位,不会出现问题。

代码

vi l, r, g[maxn];
int color[maxn];
ll ans[maxn];
int n, pos[maxn];
void dfs (int now, int fa, bool col)
{
    if (col) l.pb (now);
    else r.pb (now);
    color[now] = col;
    for (auto i : g[now]) if (i != fa) {
        dfs (i, now, !col);
    }
}
signed main ( )
{
    cin >> n;
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        g[u].pb (v), g[v].pb (u);
    }
    dfs (1, 0, 1);
    if (l.size ( ) > r.size ( )) swap (l, r);
    ll tmp = (1LL << 60) - 1;
    fill (ans + 1, ans + n + 1, tmp);
    for (auto i : l) ans[i] ^= (1LL << 55);
    for (auto i : r) {
        ans[i] ^= ((1LL << 50) - 1);
        ans[i] ^= (2LL << 55);
    }
    for (int i = 0; i < l.size ( ); ++i) {
        ans[l[i]] ^= (1LL << i);
        for (auto j : g[l[i]]) {
            ans[j] |= (1LL << i);
        }
        pos[l[i]] = i;
    }
    for (int i = 1; i <= n; ++i)
        cout << ans[i] << (i == n ? endl : ' ');
    return 0;
}
上一篇:大厂运维必备技能:PB级数据仓库性能调优


下一篇:PB 水凝胶基普鲁士蓝纳米复合物|碳纳米管-离子液体/聚苯胺-普鲁士蓝-普鲁士蓝氧化酶复合物|碳纳米管/普鲁士蓝(MWCNTs/PB)纳米复合物