[CF1286B] Numbers on Tree

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

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]<<" ";
    }
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12550069.html