题意
给了一个长度为n的数组a,输出两个排列.
如果
,则要求在输出的排列中,a[i]要比i的值更小.
分别输出满足要求的排列中字典序最小和字典序最大的排列.
考虑从a[i]向i连边,然后就可以用优先队列跑拓扑排序了
然后有关第一问,其实是有 解法的,考虑从1到n枚举每个数,然后将它之前的点都赋值,遇到已经赋值过的点就停下来.赋值的要求是从大到小,比较好理解.
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n;
int fa[maxn],ans[maxn],vis[maxn],du[maxn],rt,cnt;
vector<int> e[maxn];
bool cmp(int a,int b){return a>b;}
priority_queue<int,vector<int>,less<int> > q;
void bfs(){
while(!q.empty())q.pop();
for(int i=1;i<=n;i++){
if(!du[i])q.push(i);
}
while(!q.empty()){
int u=q.top();q.pop();ans[u]=++cnt;
for(int i=0;i<e[u].size();i++){
int v=e[u][i];
du[v]--;
if(du[v]==0)q.push(v);
}
}
}
int main(){
//freopen("3.in","r",stdin);
//freopen("3.out","w",stdout);
n=read();
for(int i=1;i<=n;i++){
fa[i]=read();
if(fa[i])
du[i]++;
}
int cnt=0;
for(int i=1;i<=n;i++){
int u=i;
if(ans[u])continue;
while(u){
if(ans[u])break;
cnt++;
u=fa[u];
}
u=fa[i];
ans[i]=cnt;
int now=ans[i]-1;
while(u){
if(ans[u])break;
ans[u]=now;now--;
u=fa[u];
}
}
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
puts("");
memset(vis,0,sizeof(vis));
memset(ans,0,sizeof(ans));
cnt=0;
for(int i=1;i<=n;i++){
e[fa[i]].push_back(i);
}
bfs();
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
return 0;
}