CF2215C 思路分享(通信)
https://codeforces.com/problemset/problem/2215/C
题意概述
这是一道通信题.
First Run
给定一棵节点数为 \(n\) 的无根树和 \(s\),随后给出 \(n-1\) 条边,需要给边定向,每读入一条边就要立刻输出该边的方向.
\(3\le n \le 30,1\le s \le 2^{n-1}\).
Second Run
给定 \(n\) 和 First Run 中构造的图,输出 \(s\).
思路
可以发现 \(s\) 有 \(2^{n-1}\) 种可能的取值,同时边定向的方案也恰好有 \(2^{n-1}\) 种,考虑用边来刻画 \(s\) 的每一位.
令 \(s' = s-1\),这样范围就是 \([0,2^{n-1})\),需要 \(n-1\) 位.
将 \(s'\) 的每一位映射到 \(a_2,a_3,\cdots,a_n\) 上,特别地,令 \(a_1=0\).
对于每一条边 \((u,v)\),如果 \(a[u]=a[v]\),就让小编号指向大编号;否则就让大编号指向小编号.
在 Second Run 中,从 \(1\) 开始 DFS 构造出 \(s'\) 即可.
时间复杂度 \(\mathcal{O}(n)\).
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve1(){
int n,s;
cin >> n >> s;
s--;
vector<int> a(n+1);
a[1] = 0;
for (int i=0;i<n-1;i++){
a[i+2] = s>>i&1;
}
for (int i=0;i<n-1;i++){
int u,v;
cin >> u >> v;
if (u>v){
swap(u,v);
}
if (a[u]==a[v]){
cout << u << ' ' << v << endl;
}
else{
cout << v << ' ' << u << endl;
}
}
}
void solve2(){
int n;
cin >> n;
vector<vector<pair<int,int>>> adj(n+1);
for (int i=0;i<n-1;i++){
int u,v;
cin >> u >> v;
adj[u].emplace_back(0,v);
adj[v].emplace_back(1,u);
}
vector<int> a(n+1);
function<void(int,int)> dfs = [&](int u,int par){
for (auto& [f,v]:adj[u]){
if (v==par) continue;
a[v] = a[u]^f^(u>v);
dfs(v,u);
}
};
dfs(1,-1);
int s = 0;
for (int i=2;i<=n;i++){
s |= a[i]<<i-2;
}
cout << s+1 << endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t,q;
cin >> t >> q;
while (t--){
if (q==1){
solve1();
}
else{
solve2();
}
}
return 0;
}

浙公网安备 33010602011771号