[CF1286B] Numbers on Tree

给定一棵有根树,每个结点有权值 (a_i),记 (c_i)(i) 的子树中权值 (<a_i) 的点的个数。给定 (c_i),构造 (a_i)(nleq2000)

Solution

某个子树内的合法性只和这个子树内权值的相对大小有关,于是一定存在一种合法方案,使得所有点的权值互不相同,不妨设为一个 (n) 的全排列

于是我们考虑维护一个集合 (S),初态下 (S) 中包含所有点,设 (d_i) 表示 (i) 的子树中权值 (<a_i) 的仍然在 (S) 中的点的个数,显然初态下 (d_i=c_i)

我们每次从 (S) 中取出所有 (d_i=0) 的点,给这些点赋权

这些点之间存在祖先关系,那么显然深度浅的点应该赋小权

于是我们每次取出所有 (d_i=0) 的点把它们扔进一个堆中,每次把堆顶取出来并且给它赋权,同时给它所有祖先的 (d_i-1),如果某个祖先的 (d_i=0) 就把这个祖先扔进堆中

如果堆空了,但是还有节点没有赋权,则输出 NO

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 2005;
vector <int> g[N];
priority_queue <pair<int,int> > hp;
int ans[N],n,p[N],c[N],d[N],fa[N],ind,dep[N];

void dfs(int p) {
    for(int q:g[p]) if(dep[q]==0) {
        dep[q]=dep[p]+1;
        fa[q]=p;
        dfs(q);
    }
}

signed main() {
    cin>>n;
    for(int i=1;i<=n;i++) cin>>p[i]>>c[i];
    for(int i=1;i<=n;i++) g[p[i]].push_back(i);
    for(int i=1;i<=n;i++) d[i]=c[i];
    int r=0;
    for(int i=1;i<=n;i++) if(p[i]==0) r=i;
    dfs(r);
    for(int i=1;i<=n;i++) if(d[i]==0) hp.push({-dep[i],i});
    while(hp.size()) {
        int p=hp.top().second;
        hp.pop();
        ans[p]=++ind;
        while(p!=r) {
            p=fa[p];
            d[p]--;
            if(d[p]==0 && !ans[p]) hp.push({-dep[p],p});
        }
    }
    if(ind<n) {
        puts("NO");
    }
    else {
        puts("YES");
        for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/12550069.html