zoukankan      html  css  js  c++  java
  • codeforces 980E The Number Games

    codeforces 980E

    题目大意:

    题目大意 : 有一棵点数为 n 的数,第 ii 个点的点权是 2i 你需要删掉 k 个点,使得删掉这些点后树依然联通,且剩下的点权之和最大,并输出方案

    n,k≤1000000

    解题思路 :

    该问题可以转化为选取 n−k个点,使得选取的点联通且权值和最大

    根据点权是 2i,有选取编号为 x 的点比选取 i=[1,x)之间的所有点还要优(手推一下就知道啦)

    首先 n 一定要保留,于是可以将 n设置为 root 把无根树变成有根树来简化问题

    接下来不妨贪心的从大到小枚举点,对于当前的点,判断是否已经被标记,如果没有被标记,那么就找到离当前点最远的没有被标记的祖先,

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

    所以对于一个点 x 只需要倍增找到其到 root 路径上最深的未被选取的点 y

    那么路径上没有被选取的点的个数就是 dep[x]-dep[y]+1如果可以选取就dfs枚举这些点并标记为取。

    因为每个点只会被最多选取一次,总复杂度是 O(nlogn)

    var
    a,next,head,dep:array[0..2000005]of longint;
    f:array[0..1000005,0..24]of longint;
    vis:array[0..2000005]of boolean;
    i,n,m,k,e,root,u,v,fi,j,x,y:longint;
    procedure add(x,y:longint);
     begin
      inc(e);a[e]:=y;next[e]:=head[x];head[x]:=e;
     end;
     procedure dfs(x:longint);//预处理深度
      var i,v:longint;
       begin
       i:=head[x];
       while i>0 do
        begin
         v:=a[i];
          if dep[v]=0 then
            begin
             dep[v]:=dep[x]+1;
             f[v,0]:=x;
             dfs(v);
            end;
         i:=next[i];
        end;
      end;
      function get(x:longint):longint;//找最远的未被访问的点,倍增
       var i:longint;
       begin
         for i:=22 downto  0 do
         begin
          if (not(vis[f[x,i]]))and(f[x,i]<>0)then  x:=f[x,i];
         end;
         exit(x);
       end;
       procedure redfs(u,x:longint);//向上标记点
        var i:longint;
         begin
          vis[u]:=true;
          if u=x then exit;
          redfs(f[u,0],x);
         end;
    begin
     readln(n,k);k:=n-k-1;//节点n占掉一个位子
     for i:=1 to n-1 do
      begin
       readln(x,y);
       add(x,y);
       add(y,x);
      end;
     root:=n;
     f[root,0]:=root;//预处理
     dep[root]:=1;
     dfs(root);
    
     for i:=1 to 22 do
      for j:=1 to n do
        begin
         f[j,i]:=f[f[j,i-1],i-1];//倍增初始化
        end;
        vis[n]:=true;
      for i:=n-1 downto 1 do
       if not vis[i]  then
        begin
          u:=i;fi:=get(u);
          if dep[u]-dep[fi]+1<=k then
            begin
             k:=k-(dep[u]-dep[fi]+1);
            // writeln(k);
             redfs(u,fi);
            end;
        end;
        for i:=1 to n do if not vis[i] then write(i,' ');
    end.
    NOIP2018 rp++
  • 相关阅读:
    如何使用RedisTemplate访问Redis数据结构
    redis 简单限流
    Caused by: org.apache.ibatis.binding.BindingException: Parameter '__frch_item_0' not found. Available parameters are [list]
    简单的根据权重随机数负载均衡算法
    后缀表达式(逆波兰表达式)计算器
    ASP.NET C# 如何在程序中控制IIS服务或应用程序池重启?
    iis7下url重写后,已存在的html不能访问了(未能执行URL)的解决方法
    IIS支持apk文件
    用vbs脚本远程登录批量交换机保存配置
    卷积神经网络入门案例-数字图像识别
  • 原文地址:https://www.cnblogs.com/brilliant107/p/9380537.html
Copyright © 2011-2022 走看看