1 条题解
-
0
自动搬运
来自洛谷,原作者为

hepp
如此成绩||不拿2级勾不删||调题相关:https://www.luogu.me/article/k3zgtcrs搬运于
2025-08-24 22:14:04,当前版本为作者最后更新于2022-04-17 20:15:29,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
这两个小题的解法不相同!
我们先看第一小题。
每个人都最多只有一个已知的比他成绩好的,我们可以把比他成绩好的人看做他的父节点,这样,我们就得到了一棵树。而这棵树的根节点是 0。
看样例,要使编号小的排在前面,我们一开始先考虑 1(不惜一切代价将未放入的编号最小的放入), 1 的祖先有 3,2 。要放入 1,就必须先放入 2,3 (他的所有祖先)。所以,现在的排名是:
NO.1 2 号
NO.2 3 号
NO.3 1 号
1,2,3 号都已排名,还剩一个 4,4 的祖先 2 已经在队伍中,所以他可以直接进入,最终排名 2 3 1 4。按照题目的排列方式(第 个数输出 的名次)答案是 3 1 2 4 。
代码如下:
#include<bits/stdc++.h> using namespace std; const int N=1e5*2+10; int ans[N],a[N],cur=0; //ans[i]指第i名的名次,a[i]是第i人的祖先,cur代表队伍中的人数。 int pm(int x) { if(ans[x]!=-1)//x以及x的祖先已经入队了 return cur; else return ans[x]=pm(a[x])+1;//递推,x是他的祖先的下一个 } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=0;i<=n;i++) ans[i]=-1; ans[0]=0; //初始化 for(int i=1;i<=n;i++) { if(ans[i]==-1)//如果他还没有进队 { ans[i]=pm(i);//让他进队 cur=ans[i];//现在有ans[i]个人在队伍中 } } for(int i=1;i<=n;i++) printf("%d ",ans[i]); printf("\n"); return 0; }第二小题
如题目所述,让编号前的同学靠后不等于编号后的同学靠前。(例如 4 0 0 0 1 应该得出的是 3 2 4 1 而不是 1 4 3 2 ) 我们在第一题时是从多点到根点,而这一题我们需要从根点到多点,类似于 bfs 和拓扑。
还是样例。与 0 联通的只有 2,所以我们只能请 2 入队。 2 入队后,他的儿子便可以入队了。他的儿子有 3,4 两位,但我们要让编号小的后入队,所以 4 先入队,接着是 3。3 的儿子——1 也解禁并入队,最终排名 2 4 3 1,答案是 4 1 3 2。
转化为代码如下:
#include<bits/stdc++.h> using namespace std; const int N=1e5*2+10; priority_queue<int> q;//优先队列,编号大的在前 int cnt[N],a[N],cur=0; vector<int>g[N]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); g[a[i]].push_back(i); } //标注出每个人的所有儿子 for(int i=0;i<=n;i++) cnt[i]=-1; //初始化 q.push(0); //与0点联通的点(没有父节点)可以进队 while(q.size()) { int u=q.top(); q.pop(); cnt[u]=cur; cur++; //在队伍中编号最大的出队并获取排名 for(int i=0;i<g[u].size();i++) q.push(g[u][i]); //u的儿子也可以获取排名了 } for(int i=1;i<=n;i++) printf("%d ",cnt[i]); return 0; }
- 1
信息
- ID
- 5079
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者