2021牛客暑期多校训练营#10:F-Train Wreck

2021牛客暑期多校训练营#10:F-Train Wreck

原题链接:https://ac.nowcoder.com/acm/contest/11261/F

文章目录

  • 2021牛客暑期多校训练营#10:F-Train Wreck
    • 题目大意
    • 解题思路
    • 代码实现

题目大意

有一个旧火车站,其只有死胡同轨道,可以视为一个栈,可将火车入栈或者出栈。
n ( 1 ≤ n ≤ 1 0 6 ) n(1\leq n\leq 10^6) n(1n106)辆彩色火车进站,第 i i i辆火车的颜色是 k i ( 1 ≤ k i ≤ n ) k_i(1\leq k_i\leq n) ki(1kin),进出栈顺序已定,现在你需要为每次入栈操作分配一辆火车,使得入栈时栈中其他火车颜色序列唯一。

解题思路

设入栈编号为 1 、 2 、 3 、 4 、 5 、 6 1、2、3、4、5、6 123456
2021牛客暑期多校训练营#10:F-Train Wreck_第1张图片
2021牛客暑期多校训练营#10:F-Train Wreck_第2张图片
将它构造成一棵树
2021牛客暑期多校训练营#10:F-Train Wreck_第3张图片
祖先节点合法时,当兄弟节点不相同,构造的序列肯定也是合法的所以只需要构造兄弟节点不相同的树。

还可以用向量存储出入时的序列,代替树。
我们不需要知道每个节点的父亲是谁,只要知道它们的兄弟是谁,当存入一个第 i i i层的节点,就将第 i + 1 i+1 i+1层的节点删去,就保证现在第 i i i层存储的是自己的兄弟,可以用向量存储。关于保证目前第 i i i层都是自己的兄弟,因为当自己的父亲被存储,以前存储的非此父节点的子节点都被清除,可得。

用优先队列存储每种颜色的编号和剩余数量,按数量从大到小排序,避免剩下的都是同一种颜色的情况,保证答案最优。

代码实现

#include
#define pb push_back
#define pa pair<int,int> 
using namespace std;
const int N=1e6+7;
vector<int>ve[N];
priority_queue<pa>qu;
int n,a[N],ans[N];
char c[N<<1];
void rd(int &x){int res=0;char c=getchar(),last=' ';while(c>'9'||c<'0')last=c,c=getchar();while(c<='9'&&c>='0')res=res*10-'0'+c,c=getchar();x=last=='-'?-res:res;}
void calc(vector<int> a)
{
	vector<pa>v;
	for(auto x:a)
	{
		if(qu.empty()){puts("NO");exit(0);}//为空,表示无颜色可填,输出NO
		auto u=qu.top();qu.pop();
		ans[x]=u.second;//记录答案
		v.pb({u.first-1,u.second});//数量-1,一起存进队列
	}
	for(auto i:v)qu.push(i);
}
int main()
{
	rd(n);
	scanf("%s",c+1);
	for(int i=1;i<=n;i++){int x;rd(x),a[x]++;};
	for(int i=1;i<=n;i++)if(a[i]>0)qu.push({a[i],i});//优先队列存储编号与数量
	int top=0,cnt=0;
	for(int i=1;i<=2*n;i++)
	{
		if(c[i]=='(')ve[top++].pb(++cnt),ve[top].clear();//向量存储第top层的儿子
		else
		calc(ve[top--]);
	}
	calc(ve[top]);
	puts("YES");
	for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n?'\n':' ');
}

你可能感兴趣的:(多校联赛,c++,数据结构,队列,算法)