构造思维+树形结构 Codeforces Round #612 (Div. 2) D题 Numbers on Tree
程序员文章站
2022-07-12 13:55:04
...
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;
}