[NERC2019] Foolprüf Security 题解
题目中的编号类似于一个黑白染色的形式(树是一个二分图),下文将两种结点称为“黑点”(共有
于是可以得出无解的一个充分条件:
对于
回头考虑 Prüfer 序列的构造方式,最终留下的一条边必然是
按照如下流程构造:在
优先队列维护这个过程可以做到
放代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n,m,ka,kb; cin>>n>>m>>ka>>kb;
if(ka>=m||kb>=n)cout<<"No\n",exit(0);
vector<int> a(ka),b(kb),d(n+m);
for(auto &i:a)cin>>i,d[--i]++;
for(auto &i:b)cin>>i,d[--i]++;
while(a.size()<m-1)a.emplace_back(0),d[0]++;
while(b.size()<n-1)b.emplace_back(n),d[n]++;
// 补全 a 和 b 两个序列
d[a.back()]++,d[b.back()]++; // 相当于设为了正无穷
vector<pair<int,int> > e;
int c=-1,p=0,pa=0,pb=0;
while(e.size()<n+m-2){
while(d[p])p++;
if(c<0||c>=p)c=p++;
int t=c<n?b[pb++]:a[pa++];
e.emplace_back(c,t),c=--d[t]?-1:t;
} // 使用模板题题解的技巧优化到 O(n)
e.emplace_back(a.back(),b.back());
cout<<"Yes\n";
for(auto [u,v]:e)cout<<u+1<<' '<<v+1<<'\n';
return 0;
}