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;
}
posted @ 2026-06-11 14:56  kzssCCC  阅读(14)  评论(0)    收藏  举报