标签:class 多选 dep col 最大 roo games size force
题目大意:
题目大意 : 有一棵点数为 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
标签:class 多选 dep col 最大 roo games size force
原文地址:https://www.cnblogs.com/brilliant107/p/9380537.html