题解:P14626 [2018 KAIST RUN Fall] Fake Plastic Trees
说一下我的广搜构造方法。
题意
我们要构造一棵叶子结点数为
思路
对于一棵虚假塑料树
我们可以先分解子树,存储子树大小。\ 然后将所有出现过的子树按大小从小到大排序,并用 map 映射,记录编号。\ 最后对于每一棵树,记录它的左右子树。
该方法的实际用到的非空树节点为
具体实现可以看代码。 :::success[代码]
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,k,ans,sum1[130],sum2[130];
set<int> s;
vector<int> v;
map<int,int> mp;
signed main(){
cin >> t;
while(t--){
cin >> n;
k=0;
ans=0;
s.clear();
v.clear();
mp.clear();
s.insert(n);
v.push_back(n);
while(k<v.size()){//收集子树大小
int x=v[k++];
if(x==1) continue;
int a=(x+1)/2,b=x/2;
if(s.find(a)==s.end()){
s.insert(a);
v.push_back(a);
}
if(s.find(b)==s.end()){
s.insert(b);
v.push_back(b);
}
}
sort(v.begin(),v.end());//排序
for(int i=0;i<v.size();i++){//建立映射
if(v[i]==1){
mp[v[i]]=ans++;
continue;
}
mp[v[i]]=ans++;
}
for(int i=0;i<v.size();i++){//构建每棵树的左右指针
if(v[i]==1){
sum1[mp[1]]=sum2[mp[1]]=-1;
}else{
int a=(v[i]+1)/2,b=v[i]/2;
sum1[mp[v[i]]]=mp[a];
sum2[mp[v[i]]]=mp[b];
}
}
cout << ans << '\n';
for(int i=0;i<ans;i++) cout << sum1[i] << " " << sum2[i] << '\n';
cout << mp[n] << '\n';
}
return 0;
}
:::