构造思维+树形结构 Codeforces Round #612 (Div. 2) D题 Numbers on Tree

Numbers on Tree

Evlampiy was gifted a rooted tree. The vertices of the tree are numbered from 1 to n. Each of its vertices also has an integer ai written on it. For each vertex i, Evlampiy calculated ci — the number of vertices j in the subtree of vertex i, such that aj<ai.

在这里插入图片描述
After the new year, Evlampiy could not remember what his gift was! He remembers the tree and the values of ci, but he completely forgot which integers ai were written on the vertices.

Help him to restore initial integers!


题目大意:给你一颗有根树,然后每个结点都有一个c[i]值,代表以这个 i 结点为根的子树有多少个结点的权值小于 i 结点的权值;让你构造这样一棵树,就是构造每个结点的权值,满足c[i];

构造题,永远是比较难想的;

可以假设 n 个结点的权值在 1–n 的范围,从根结点往下构造,先保证根取第 c[i]+1 大的数,然后把剩下来的数分到 i 为根的各个子树里面,dfs一遍就可以,开两个状态,一个是结点 i,一个是当前以 i 结点为根的子树所包含的权值;

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=10100;
const int M=5000100;
const LL mod=9987;
int n,rt,siz[N],head[N],cnt,c[N];
struct Node{
	int to,nex;
}edge[N*2];
void add(int p,int q){
	edge[cnt].to=q,edge[cnt].nex=head[p],head[p]=cnt++;
}
void dfs1(int p){
	siz[p]=1;
	for(int i=head[p];~i;i=edge[i].nex){
		dfs1(edge[i].to);
		siz[p]+=siz[edge[i].to];
	}
}
vector<int>ve;
int ans[N];
void dfs2(int p,vector<int>vc){
	ans[p]=vc[c[p]-1];
	int pos=0;
	for(int i=head[p];~i;i=edge[i].nex){
		int q=edge[i].to;
		vector<int>vd;
		int sum=0;
		for(int j=pos;j<vc.size();j++){
			if(j==c[p]-1){
				pos++;continue;//pos特别注意
			}
			if(++sum>siz[q]) break;
			pos++;
			vd.push_back(vc[j]);
		}
		dfs2(q,vd);
	}
}
int main(){
	memset(head,-1,sizeof(head));
	cin>>n;
	for(int i=1;i<=n;i++){
		int p;cin>>p>>c[i];c[i]++;
		if(p!=0) add(p,i);
		else rt=i;
	}
	dfs1(rt);
	for(int i=1;i<=n;i++){
		if(c[i]>siz[i]){
			printf("NO\n");
			return 0;
		}
	}
	for(int i=0;i<n;i++) ve.push_back(i+1);
	dfs2(rt,ve);
	cout<<"YES"<<endl;
	for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值