• 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;
      }
      
  • 相关阅读:
    工作中,怎么做好规范
    每日一链
    模仿电子商务垂直菜单
    电脑不同的分辨率自适应显示
    怎样成为一位合格的程序员
    巅峰极客线上第一场ctf——RE
    恶意代码分析常见Windows函数
    巅峰极客线上第二场部分ctf
    恶意代码分析:虚拟网络环境配置
    0ctf2017 pwn babyheap
  • 原文地址:https://www.cnblogs.com/lr599909928/p/15560039.html
Copyright © 2020-2023  润新知