codeforces 980E The Number Games

Posted brilliant107

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codeforces 980E The Number Games相关的知识,希望对你有一定的参考价值。

题目大意:

题目大意 : 有一棵点数为 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.

 

以上是关于codeforces 980E The Number Games的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #606 (Div. 2) D. Let's Play the Words?(贪心+map)

Codeforces 950D A Leapfrog in the Array ( 思维 && 模拟 )

CodeForces 622B The Time

Educational Codeforces Round 7 F - The Sum of the k-th Powers 拉格朗日插值

The CPU_ NUM is not specified, you should set CPU_ NUM in the environment variable list。 CPU NUM

Codeforces Round #568 Div.2