返回顶部

Codeforces Round #754 (Div. 2) D. Treelabeling (二分图,二进制)

D. Treelabeling

  • 题意:给你一颗\(n\)个节点的树,让你给每个点赋不同值\([1,n]\),博弈,先手先选起点\(u\),之后每次选相邻的点\(v\),同时满足\(u \oplus v\le min(u,v)\).问你如何赋值,使得先手选择并且能赢的起点最多.

  • 题解:先看\(u\oplus v\le min(u,v)\)这个条件,很简单,只有当两个数最高位同位才成立,那么也就自然能得一个想法,我们让相邻的点最高位不同,也就是二分图黑白染色,那么先手无论选哪个点都是必赢,不难发现,对于每个最高位的数有:\(2^0,2^1,2^2,....,n-2^k+1\)个,对于某一种颜色的个数,我们一定可以用最高位不同的数的个数凑出来(想象成二进制,一定是可以的).也就是实现麻烦点,我代码写的比较丑qwq。

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    vector<int> edge[N];
    int color[N];
    int lg[N];
    int ans[N];
    int vis[N];
     
    void lg_init(){
        for(int i=1;i<=200000;++i){
            int k=0;
            while(1<<(k+1)<=i) k++;
            lg[i]=k;
        }
    }
     
    void dfs(int u,int fa,int c){
        color[u]=c;
        for(auto to:edge[u]){
            if(to==fa) continue;
            dfs(to,u,c^1);
        }
    }
     
    int main() {
        lg_init(); 
        int _;
        scanf("%d",&_);
        while(_--){
            int n;
            scanf("%d",&n);
            unordered_map<int,int> mp;
            for(int i=1;i<n;++i){
                int u,v;
                scanf("%d %d",&u,&v);
                edge[u].pb(v);
                edge[v].pb(u);
            }
            for(int i=1;i<=n;++i){
                mp[lg[i]]++;
            }
            dfs(1,-1,0); 
            int cnt0=0;
            vector<int> v;
            for(int i=1;i<=n;++i) if(color[i]==0) cnt0++;
            for(int i=lg[n];i>=0;--i){
                if(cnt0>=mp[i]){
                    cnt0-=mp[i];
                    int now=pow(2,i);
                    for(int j=0;j<mp[i];++j){
                        v.pb(now+j);
                        vis[now+j]=true;
                    }
                }
            }
            int p=0;
            vector<int> res;
            for(int i=1;i<=n;++i){
                if(color[i]==0) ans[i]=v[p++];
                if(!vis[i]) res.pb(i);
            }
            p=0;
            for(int i=1;i<=n;++i){
                if(color[i]==1) ans[i]=res[p++];
            }
            for(int i=1;i<=n;++i) printf("%d ",ans[i]);
            puts("");
            for(int i=1;i<=n;++i){
                vis[i]=false;
            }
            for(int i=1;i<=n;++i) edge[i].clear();
            mp.clear();
            v.clear();
        }
        return 0;
    }
    
posted @ 2021-11-16 10:48  Rayotaku  阅读(175)  评论(0编辑  收藏  举报