牛客暑期营2K Solution

题目链接

题解

令未给出的\(b_i=b_{i-1}+1\),模拟单调栈可得若干大小关系(若出栈则说明当前元素\(<\)栈顶元素,反之亦然)。若\(a_i>a_j\),则由\(i\)\(j\)连一条有向边,拓扑排序可得出排序后的排列。易证边数\(\le 2n\),因此时间复杂度为\(O(nlogn)\)\(p,x\)需自行排序)。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=3e6+10;
struct node {int x,y;} a[N];
int ans[N],st[N],top,in[N],n,k;
int fst[N],nxt[M],v[M],cnt;
bool vis[N];
queue<int> q;
bool cmp(node x,node y) {return x.x<y.x;}
void add(int x,int y)
{
	v[++cnt]=y; in[y]++;
	nxt[cnt]=fst[x],fst[x]=cnt;
}
void topo()
{
	for(int i=1;i<=n;i++) 
		if(!in[i]) q.push(i);
	while(!q.empty())
	{
		int x=q.front(); q.pop();
		st[++top]=x;
		for(int i=fst[x];i;i=nxt[i])
		{
			int y=v[i]; in[y]--;
			if(!in[y]) q.push(y);
		}
	}
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=k;i++) {scanf("%d%d",&a[i].x,&a[i].y); vis[a[i].x]=1;}
	for(int i=1;i<=n;i++) 
		if(!vis[i]) a[++k]=(node){i,0};
	sort(a+1,a+k+1,cmp);
	for(int i=1;i<=n;i++) 
		if(!vis[i]) a[i].y=a[i-1].y+1;
	for(int i=1;i<=k;i++)
	{
		if(a[i].y>i || a[i-1].y+1<a[i].y) {printf("-1"); return 0;}
		while(top>=a[i].y) {add(st[top],i); top--;}
		add(i,st[top]); st[++top]=i;
	}
	top=0; topo();
	if(top<n) {printf("-1"); return 0;}
	for(int i=1;i<=top;i++) ans[st[i]]=n-i+1;
	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
	return 0;
}
posted @ 2021-07-20 12:47  violet_holmes  阅读(29)  评论(0编辑  收藏  举报