• codeforces 980E The Number Games


    题意:

    给出一棵树,要求去掉k个点,使得剩下的还是一棵树,并且要求Σ(2^i)最大,i是剩下的节点的编号。

    思路:

    要使得剩下的点的2的幂的和最大,那么肯定要保住大的点,这是贪心。

    考虑去掉哪些点的话,那么去掉一个点,它相连的子树的点肯定都得去掉,很麻烦。

    所以放过来考虑保留哪些点,那么就从大到小考虑是否保留当前的点。并且把保留的点做标记。

    首先n这个点是肯定可以保留的,标记,然后依次考虑n-1,n-2。。。1。

    对于当前的点,判断是否已经被标记,如果没有被标记,那么就找到离当前点最远的没有被标记的祖先,如果要标记这个点,那么总共增加的点就是从当前点到离当前点最远的没有被标记的祖先的路径上的所有点的数量,也可以解释为当前点到已经保留的点所构成的树的路径上的点。

    找这个路径的时候,暴力的话,n^2,肯定会T,所以可以首先用倍增预处理,再来找祖先,复杂度就可以下降为O(nlogn)。

    如果这个数量没有超过要求,那么就把路径上的点全部标记。

    最后没有标记的点就是要抛弃的点。

    代码:

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <algorithm>
     4 #include <vector>
     5 using namespace std;
     6 const int N = 1e6 + 10;
     7 int n,k;
     8 vector<int> g[N];
     9 int fa[N];
    10 int dep[N];
    11 bool vis[N];
    12 int anc[N][35];
    13 void dfs(int u,int f)
    14 {
    15     fa[u] = f;
    16     for (int v : g[u])
    17     {
    18         if (v != f)
    19         {
    20             dep[v] = dep[u] + 1;
    21             dfs(v,u);
    22         }
    23     }
    24 }
    25 void rdfs(int u,int f)
    26 {
    27     vis[u] = 1;
    28     if (u == f) return;
    29     rdfs(fa[u],f);
    30 }
    31 void preprocess()
    32 {
    33     for (int i = 0;i < n;i++)
    34     {
    35         anc[i][0] = fa[i];
    36         for (int j = 1;(1<<j) < n;j++) anc[i][j] = -1;
    37     }
    38     for (int j = 1;(1<<j) < n;j++)
    39     {
    40         for (int i = 0;i < n;i++)
    41         {
    42             if (anc[i][j-1] != -1)
    43             {
    44                 int a = anc[i][j-1];
    45                 anc[i][j] = anc[a][j-1];
    46             }
    47         }
    48     }
    49 }
    50 int main()
    51 {
    52     memset(anc,-1,sizeof(anc));
    53     scanf("%d%d",&n,&k);
    54     k = n - k;
    55     for (int i = 1;i < n;i++)
    56     {
    57         int x,y;
    58         scanf("%d%d",&x,&y);
    59         x--,y--;
    60         g[x].push_back(y);
    61         g[y].push_back(x);
    62     }
    63     dfs(n-1,-1);
    64     preprocess();
    65     int num = 1;
    66     vis[n-1] = 1;
    67     for (int i = n - 2;i >= 0;i--)
    68     {
    69         if (vis[i]) continue;
    70         int t = i;
    71         for (int j = 20;j >= 0;j--)//j是从大到小枚举
    72         {
    73             if (anc[t][j] == -1) continue;
    74             else
    75             {
    76                 if (!vis[anc[t][j]])
    77                 {
    78                     t = anc[t][j];
    79                 }
    80             }
    81         }
    82         if (dep[i] - dep[t] + 1 + num <= k)
    83         {
    84             num += dep[i] - dep[t] + 1;
    85             rdfs(i,t);
    86         }
    87     }
    88     for (int i = 0;i < n;i++)
    89     {
    90         if (!vis[i]) printf("%d ",i+1);
    91     }
    92     return 0;
    93 }
  • 相关阅读:
    文件输入使System.out.println("程序执行完毕!");这句话的内容输入到文件中
    TI CC2541.h的头文件 for IAR
    状态添加Android游戏开发十日通(4)行走,跳跃,碰撞检测
    命令分析分析企业内连接Exchange 移动设备!
    寄存器数据问题反馈集锦W5200/W5300相关
    发票选择SAP 校验发票时:科目5101140100已设置为与税务不相关
    重写方法Android中的HttpsURLConnection连接
    生成数组C面试题精选
    函数路径Croc Champ 2013 Round 2 题解java教程
    排名中国重读“发展Linux,中日两国之比较”有感java教程
  • 原文地址:https://www.cnblogs.com/kickit/p/9015697.html
Copyright © 2020-2023  润新知