題意
給了一個長度爲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;
}