CF980E The Number Games

題目鏈接

題意分析

對於這道題 能留下大的儘量留下大的

我們以n爲根 根是必選的

然後從大到小 如果當前點i未被留下 並且留下i到根n的所有點不會超過n-k 那麼就全部留下

對於判斷的話 由於一個點i被留下 那麼i的祖先節點也會被留下

所以對於未被留下的點 我們使用倍增確定i往上最近的未被留下的點 複雜度O(nlogn)

然後暴力染色 由於每一個點只會被染色一次 所以複雜度是O(n)

CODE:

#include<bits/stdc++.h>
#define M 2008611
#define INF 200080
using namespace std;
int n,k,tot,cnt;
int to[M],nex[M],head[M];
int dep[M],fa[M][22];
bool tag[M];
void add(int x,int y)
{to[++tot]=y;nex[tot]=head[x];head[x]=tot;}
void dfs(int now,int fat)
{
	dep[now]=dep[fat]+1;fa[now][0]=fat;
	for(int i=1;(1<<i)<=dep[now];++i)
	fa[now][i]=fa[fa[now][i-1]][i-1];
	for(int i=head[now];i;i=nex[i])
	{
		int v=to[i];
		if(v==fat) continue;
		dfs(v,now);
	}
}
int query(int now)
{
	int tmp=now;
//	printf("now is fro %d\n",now);
	for(int i=20;i>=0;--i)
	{
		if((1<<i)>dep[tmp]) continue;
		if(fa[tmp][i]&&!tag[fa[tmp][i]]) tmp=fa[tmp][i];
	}
//	printf("now is to %d\n",tmp);
	return dep[now]-dep[tmp]+1;
}
void update(int now)
{
	while(tag[now]==0)
	{
		tag[now]=1;++cnt;
		now=fa[now][0];
	}
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1,x,y;i<n;++i)
	{
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
	dfs(n,0);
	cnt=1;tag[n]=1;
	for(int i=n-1;i;--i)
	{
		if(tag[i]) continue;
		int tmp=query(i);
//		printf("now is %d %d\n",tmp,cnt);
		if(tmp+cnt<=n-k) update(i);
		if(n-k==cnt) break;
	}
	for(int i=1;i<=n;++i) if(!tag[i]) printf("%d ",i);
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章