题解 CF798E 【Mike and code of a permutation】
bellmanford · · 题解
显然可以通过模拟编码
暴力连边空间和时间都是
然而我们并不需要把图建出来,如果采用 dfs 来实现拓扑排序就只需要关心当前访问到的点在反图中能连到哪些点。
建立一个
虽然连向的点是可以确定的,但是边数实际上是
#include<bits/stdc++.h>
using namespace std;
const int M=5e5+5;
int min(int x,int y){ return x<y?x:y; }
int max(int x,int y){ return x>y?x:y; }
int n,num=0,a[M],b[M],val[M];
int read(){
int x=0,y=1;char ch=getchar();
while(ch<'0'||ch>'9') y=(ch=='-')?-1:1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*y;
}
namespace SegTree{
int sum[M<<2],maxn[M<<2];
void pushup(int u){ maxn[u]=max(maxn[u<<1],maxn[u<<1|1]); }
void Build(int u,int l,int r){
sum[u]=r-l+1;
if(l==r) return (void)(maxn[u]=b[l]);
int mid=(l+r)>>1;
Build(u<<1,l,mid),Build(u<<1|1,mid+1,r);
pushup(u);
}
void Del(int u,int l,int r,int x){
sum[u]--;
if(l==r) return (void)(maxn[u]=0);
int mid=(l+r)>>1;
if(x<=mid) Del(u<<1,l,mid,x);
else Del(u<<1|1,mid+1,r,x);
pushup(u);
}
int Find(int u,int l,int r,int L,int R,int x){
if(l>R||r<L||!sum[u]||maxn[u]<=x||L>R) return -1;
if(l==r) return l;
int mid=(l+r)>>1;
int res=Find(u<<1,l,mid,L,R,x);
if(res==-1) res=Find(u<<1|1,mid+1,r,L,R,x);
return res;
}
}using namespace SegTree;
void dfs_topo(int u){
if(!val[b[u]]&&b[u]<=n) dfs_topo(b[u]);
int las=0;
while(1){
int v=Find(1,1,n,las+1,a[u]-1,u);
if(v==-1) return (void)(Del(1,1,n,u),val[u]=++num);
las=v;if(v==u) continue ;
dfs_topo(v);
}
val[u]=++num;Del(1,1,n,u);
}
void solve(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
if(a[i]==-1) a[i]=n+1;
b[a[i]]=i;
}
for(int i=1;i<=n;i++) if(!b[i]) b[i]=n+1;Build(1,1,n);
for(int i=1;i<=n;i++) if(!val[i]) dfs_topo(i);
for(int i=1;i<=n;i++) printf("%d ",val[i]);printf("\n");
}
signed main(){
solve();
}