算出每个点取值的范围:1~maxx_i。把没用的点从小到大放在一个数组里,按照maxx_i顺序扫描。
如果当前maxx_i=k的仅有一个点,且在1~k中只有一个数可用,那么这个节点的值确定了。
如果maxx_i=k的节点数==在1~k中可用的数的数量,很明显之前的节点会把这些数占满,1~k中可用的数全置为不可用。
复杂度:O(n)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=1000005;
int node[Maxn],next[Maxn],a[Maxn],dig[Maxn];
int z[Maxn],q[Maxn],sum[Maxn],p[Maxn],fa[Maxn];
int n,i,j,tot,root,N,head,l,r,t,maxx[Maxn],id[Maxn];
int read(){
char ch=getchar();
int ret=0;
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9')
{ret=ret*10+ch-'0'; ch=getchar();}
return ret;
}
void add(int x,int y)
{ node[++tot]=y; next[tot]=a[x]; a[x]=tot; }
int gf(int x){
int xx=x, xxx;
while (xx!=fa[xx]) xx=fa[xx];
while (x!=xx) xxx=x, x=fa[x], fa[xxx]=xx;
return xx;
}
void bfs(){
for (q[l=r=1]=root;l<=r;l++)
for (i=a[q[l]];i;i=next[i])
q[++r]=node[i];
for (i=1;i<=n;i++){
if (maxx[ q[i] ]>0) continue;
//t = maxx[ q[i] ] =lower_bound( dig+1,dig+N+1,maxx[ p[q[i]] ]-1 )-dig;
t = maxx[ q[i] ] = gf( maxx[ p[q[i]] ]-1 );
//go[i]=tb[t]; tb[t]=i;
sum[t]++; if (sum[t]==1) id[t]=q[i];
}
}
int main(){
freopen("pen.in","r",stdin);
freopen("pen.out","w",stdout);
//scanf("%d",&n);
n=read();
for (i=1;i<=n;i++) fa[i]=i;
for (i=1;i<=n;i++){
//scanf("%d%d",&p[i],&z[i]);
p[i]=read(); z[i]=read();
if (i!=p[i]) add(p[i],i);
else root=i;
if (z[i]>0) maxx[i]=z[i], fa[z[i]]=z[i]-1;
}
z[root]=n; maxx[root]=n; fa[n]=n-1;
for (i=1;i<=n;i++)
if (fa[i]==i) dig[++N]=i;
bfs();
//for (i=1;i<=n;i++) printf("%d\n",maxx[i]);
//printf("\n");
for (i=1,j=head=1;i<=n&&head<=N;i++){
//printf("%d\n",j);
for (;j<=N&&dig[j]<=i;j++);
if (sum[i]==1 && j-head==1)
z[ id[i] ]=dig[j-1];
if (sum[i-1]+sum[i]==j-head)
head=j, sum[i]=0;
else sum[i]+=sum[i-1];
}
for (i=1;i<=n;i++) printf("%d\n",z[i]);
return 0;
}