bzoj 5026

题目链接

题意

给了一个长度为n的数组a,输出两个排列.
如果 a [ i ] ! = 0 a[i]!=0 ,则要求在输出的排列中,a[i]要比i的值更小.
分别输出满足要求的排列中字典序最小和字典序最大的排列.

考虑从a[i]向i连边,然后就可以用优先队列跑拓扑排序了

然后有关第一问,其实是有 O ( n ) O(n) 解法的,考虑从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;
}

发布了95 篇原创文章 · 获赞 9 · 访问量 3208

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/103936005