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)\),这样的数据结构一个都想不出来就退役吧,我们有三个候选数据结构,分别是:
- 数组,单次插入\(O(n)\),单次查找\(O(logn)\)
- 链表,单次插入\(O(1)\),单次查找\(O(n)\)
- 平衡树,单次插入\(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;
}
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。