标签:for inline 方案 维护 queue sign lse number efi
给定一棵有根树,每个结点有权值 \(a_i\),记 \(c_i\) 为 \(i\) 的子树中权值 \(<a_i\) 的点的个数。给定 \(c_i\),构造 \(a_i\)。\(n\leq2000\)
某个子树内的合法性只和这个子树内权值的相对大小有关,于是一定存在一种合法方案,使得所有点的权值互不相同,不妨设为一个 \(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]<<" ";
}
}
标签:for inline 方案 维护 queue sign lse number efi
原文地址:https://www.cnblogs.com/mollnn/p/12550069.html