Codeforces 1286B. Numbers on Tree题解

题目链接:Codeforces 1286B. Numbers on Tree
题目大意:博主太懒了不想打了,大家去洛谷上看吧
题解:首先,我们考虑无解的情况,很明显,当有一个点的\(c_i\)大于等于这个点的字数大小时,肯定无解。否则,当每个节点的值不同时,一定有解,证明显然。
题目中的限制是每个数在\(1\) ~ \(10^9\)之间,但是没有意义,可以离散化变成\(1,2,\cdots,n\)的(虽然说我直接构造 \(1\sim n\))。注意到这一题的权值与答案没有关系,我们所需的仅仅只是在每个权值不同时它们之间的大小关系
很明显,叶子节点之间的大小关系时不影响答案的,那么我们可以给叶子节点之间的大小随便选。那么对于每一个非叶节点来说,在它的子树之间的大小全部被处理出来时,它只需要在将子树中的两个点拿出来,将自己的权值放在它们之间就可以了。
如果一开始就给节点赋值,最后很有可能会导致某个节点插在了两个相邻的权值之间,会出现浮点数,这很讨厌,所以,我们一开始不给节点赋值,只考虑维护权值之间的大小关系。
思考一种能够维护数列大小关系的数据结构,支持动态插入一个元素,要求插入时间复杂度不超过\(O(n)\),查找时间复杂度不超过\(O(n)\)这样的数据结构一个都想不出来就退役吧,我们有三个候选数据结构,分别是:

  1. 数组,单次插入\(O(n)\),单次查找\(O(logn)\)
  2. 链表,单次插入\(O(1)\),单次查找\(O(n)\)
  3. 平衡树,单次插入\(O(logn)\),单次查找\(O(logn)\)

我选用的是第二种,因为我觉得在动态插入时,链表更加直观。
所以到这里,思路就很清晰了,先将所有叶子节点用链表链接起来,然后考虑它们的父亲插在哪儿,再往上推一层,……,这样下去,就可以得到所有节点之间的大小关系,然后,遍历一遍链表,按大小关系赋值即可,时间复杂度\(O(n^2)\)

下面是代码:

#include <cstdio>
const int Maxn=2000;
int sz[Maxn+5];
int fa[Maxn+5];
int head[Maxn+5],arrive[Maxn+5],e_nxt[Maxn+5],tot;
void add_edge(int from,int to){
	arrive[++tot]=to;
	e_nxt[tot]=head[from];
	head[from]=tot;
}
int n,Root;
int c[Maxn+5];
int nxt[Maxn+5],pre[Maxn+5];
int lea[Maxn+5],lea_len;
int a[Maxn+5];
int dfn[Maxn+5],out[Maxn+5],dfn_tot;
void init_dfs(int u){
	sz[u]=1;
	for(int i=head[u];i;i=e_nxt[i]){
		int v=arrive[i];
		init_dfs(v);
		sz[u]+=sz[v];
	}
	if(sz[u]==1){
		lea[++lea_len]=u;
	}
}
void dfs(int u){
	dfn[u]=++dfn_tot;
	for(int i=head[u];i;i=e_nxt[i]){
		int v=arrive[i];
		dfs(v);
	}
	out[u]=dfn_tot;
	if(sz[u]==1){
		return;
	}
	int pos=0;
	int num=0;
	while(num<c[u]||(num==c[u]&&c[u]!=sz[u]-1)){
		pos=nxt[pos];
		if(dfn[u]<=dfn[pos]&&out[u]>=dfn[pos]){
			num++;
		}
	}
	if(c[u]==sz[u]-1){
		pos=nxt[pos];
	}
	int las=pre[pos];
	nxt[u]=pos;
	pre[u]=las;
	nxt[las]=u;
	pre[pos]=u;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&fa[i],&c[i]);
		if(fa[i]==0){
			Root=i;
		}
		add_edge(fa[i],i);
	}
	init_dfs(Root);
	lea[lea_len+1]=n+1;
	for(int i=1;i<=lea_len;i++){
		pre[lea[i]]=lea[i-1];
		nxt[lea[i]]=lea[i+1];
	}
	nxt[0]=lea[1];
	pre[n+1]=lea[lea_len];
	for(int i=1;i<=n;i++){
		if(c[i]>=sz[i]){
			puts("NO");
			return 0;
		}
	}
	dfs(Root);
	int id_tot=0;
	int pos=nxt[0];
	while(pos!=n+1){
		a[pos]=++id_tot;
		pos=nxt[pos];
	}
	puts("YES");
	for(int i=1;i<=n;i++){
		printf("%d ",a[i]);
	}
	puts("");
	return 0;
}
posted @ 2020-02-08 21:12  with_hope  阅读(264)  评论(0编辑  收藏  举报