bzoj 5026

題目鏈接

題意

給了一個長度爲n的數組a,輸出兩個排列.
如果a[i]!=0a[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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章