2020 ICPC济南站 J Tree Constructer 构造+二分图染色

原题链接

文章目录

题意

有n个点的图中,满足如果两个点的权值或运算之后等于260 -1,则两点之间可以连边。题中会给n-1条边,问每个点权应该是多少。

分析

由于n的范围非常小,可以直接考虑每一位上的构造。

=
我们采用如上构造方式,我们先给每个节点编号,但要保证白色为个数少的那个,从而确保60位上可以任意选择。

  1. 对于白色的点,我们先将最高位置0,在让第id位也置0,其余为1,这样可以保证所有白色点之间不会有边
  2. 对于所有黑的的点,我们先将最高位置1,再与它相邻的所有点的第id位置1,其余为0,从而确保与所有相邻的白色节点都满足条件。

Code

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 200, M = 5e5 + 10, INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
vector<int> vec[2], g[N];
int n, id[N];
ll ans[N];
void dfs(int x, int fa, int color) {
    
    
    vec[color].push_back(x);
    for (auto v : g[x]) {
    
    
        if (v == fa) continue;
        dfs(v, x, color^1);
    }
}

void solve() {
    
    
    cin >> n;
    for (int i = 1; i <= n-1; i++) {
    
    
        int u, v; cin >> u >> v;
        g[u].push_back(v), g[v].push_back(u);
    }
    dfs(1, 0, 1);
    if (vec[0].size() > vec[1].size()) swap(vec[0], vec[1]);
    for (int i = 0; i < vec[0].size(); i++) {
    
    
        ans[vec[0][i]] = (1ll << 60) - 1 - (1ll << i) - (1ll << 59);
        id[vec[0][i]] = i;
    }
    for (int i = 0; i < vec[1].size(); i++) {
    
    
        id[vec[1][i]] = i;
        ll tmp = (1ll<<59);
        for (auto v : g[vec[1][i]]) {
    
    
            tmp += (1ll << id[v]);
        }
        ans[vec[1][i]] = tmp;
    }
    for (int i = 1; i <= n; i++) printf("%lld ", ans[i]);
}

signed main() {
    
    
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("Test/input", "r", stdin);
    freopen("Test/output", "w", stdout);
#endif
    solve();
    return 0;
}

赛中最后想到构造方法但没注意到一些细节就一直没过,一定要确定一个小的块!!!

猜你喜欢

转载自blog.csdn.net/kaka03200/article/details/111826684
今日推荐