• [CF980E]The Number Games——贪心+倍增


    题目链接:

    [CF980E]The Number Games

    题目大意:

    给出一棵$n$个节点的树,第$i$个节点权值为$2^i$,要求删除$k$个点且保证剩下点联通情况下权值和最大。

    首先可以想到一定先选大的,那么节点$n$必须选,剩下的从大到小依次选。

    因为需要保证联通,我们不妨以$n$为根,如果要选$i$节点,那么从$i$到根的所有点都要选。

    对于每个点是否能选只需判断从它到根需要选的节点数是否小于等于当前剩余可选节点数即可。

    朴素做法可以从点$i$往上一步一步爬,当遇到第一个已经被选的节点时,说明上面的节点都被选了,求出这段路径节点数即可。

    但这样时间复杂度会被卡成$O(n^2)$,所以我们改成倍增往上爬,时间复杂度为$O(nlogn)$。

    每选一个节点时一步一步往上爬并标记即可。

    因为每个点只会被标记一次,所以时间复杂度为$O(n)$。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define lowbit(x) (x&(-x))
    #define pr pair<int,int>
    using namespace std;
    int n,k;
    int head[1000010];
    int nex[2000010];
    int to[2000010];
    int f[1000010][20];
    int vis[1000010];
    int x,y;
    int tot;
    int res;
    int dep[1000010];
    void add(int x,int y)
    {
    	nex[++tot]=head[x];
    	head[x]=tot;
    	to[tot]=y;
    }
    void dfs(int x,int fa)
    {
    	dep[x]=dep[fa]+1;
    	f[x][0]=fa;
    	for(int i=1;i<=19;i++)
    	{
    		f[x][i]=f[f[x][i-1]][i-1];
    	}
    	for(int i=head[x];i;i=nex[i])
    	{
    		if(to[i]!=fa)
    		{
    			dfs(to[i],x);
    		}
    	}
    }
    int query(int x)
    {
    	if(vis[x])return 0;
    	int now=x;
    	for(int i=19;i>=0;i--)
    	{
    		if(!vis[f[x][i]]&&f[x][i])
    		{
    			x=f[x][i];
    		}
    	}
    	return dep[now]-dep[x]+1;
    }
    void change(int x)
    {
    	while(!vis[x])
    	{
    		vis[x]=1;
    		res++;
    		x=f[x][0];
    	}
    }
    int main()
    {
    	scanf("%d%d",&n,&k);
    	k=n-k;
    	for(int i=1;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		add(y,x);
    	}
    	dfs(n,0);
    	k--;
    	vis[n]=1;
    	res++;
    	for(int i=n-1;i>=1;i--)
    	{
    		if(k==0)break;
    		int sum=query(i);
    		if(sum<=k)
    		{
    			k-=sum;
    			change(i);
    		}
    	}
    	res=n-res;
    	for(int i=1;i<=n;i++)
    	{
    		if(!vis[i])
    		{
    			printf("%d",i);
    			res--;
    			if(res)printf(" ");
    		}
    	}
    }
  • 相关阅读:
    怎样理解 display:none 和 visibility:hidden
    怎样设置鼠标悬浮时弹出的文字提示框内容
    怎样获取当前元素节点的语言类型
    怎样控制元素节点的是否可拖动属性
    怎样读写分配给当前元素的快捷键
    怎样获取元素节点的标签名称
    怎样查看或修改元素节点的id属性
    怎样使用js将文本复制到系统粘贴板中
    怎样创建一个子树遍历器
    怎样创建一个子节点遍历器
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/14456180.html
Copyright © 2020-2023  润新知