1. 程式人生 > 其它 >【CF1044B Intersecting Subtrees】題解

【CF1044B Intersecting Subtrees】題解

題目連結

題目

這是一道互動題

你和\(Li\ Chen\)正在玩一個奇怪的遊戲。給出一棵\(N\)個點的樹,雙方分別給頂點編號為\(1\)\(N\),雙方都不知道對方給樹編號的方式。

接著雙方在自己對應的樹上選擇一個聯通子圖,在你的編號方式對應的樹上你選擇了\(x_1,x_2,...,x_{k_1}\)\(Li\ Chen\)的編號方式對應的樹上\(Li\ Chen\)選擇了\(y_1,y_2,...,y_{k_2}\),雙方都知道\(x_1,...,x_{k_1}\)\(y_1,...,y_{k_2}\)的值

現在你想知道兩個子圖是否存在至少一個公共點。你可以進行詢問,問題有以下兩種:

\(A \ x\):得到在你的編號方式下的\(x\)號點在\(Li\ Chen\)的編號方式下的值

\(B \ x\):得到在\(Li\ Chen\)的編號方式下的\(x\)號點在你的編號方式下的值

現在請你使用不多於\(5\)詢問得出是否存在公共點,或者確定兩棵子樹沒有公共點。

You are playing a strange game with Li Chen. You have a tree with $ n $ nodes drawn on a piece of paper. All nodes are unlabeled and distinguishable. Each of you independently labeled the vertices from $ 1 $ to $ n $ . Neither of you know the other's labelling of the tree.

You and Li Chen each chose a subtree (i.e., a connected subgraph) in that tree. Your subtree consists of the vertices labeled $ x_1, x_2, \ldots, x_{k_1} $ in your labeling, Li Chen's subtree consists of the vertices labeled $ y_1, y_2, \ldots, y_{k_2} $ in his labeling. The values of $ x_1, x_2, \ldots, x_{k_1} $ and $ y_1, y_2, \ldots, y_{k_2} $ are known to both of you.

The picture shows two labelings of a possible tree: yours on the left and Li Chen's on the right. The selected trees are highlighted. There are two common nodes.You want to determine whether your subtrees have at least one common vertex. Luckily, your friend Andrew knows both labelings of the tree. You can ask Andrew at most $ 5 $ questions, each of which is in one of the following two forms:

  • A x: Andrew will look at vertex $ x $ in your labeling and tell you the number of this vertex in Li Chen's labeling.
  • B y: Andrew will look at vertex $ y $ in Li Chen's labeling and tell you the number of this vertex in your labeling.

Determine whether the two subtrees have at least one common vertex after asking some questions. If there is at least one common vertex, determine one of your labels for any of the common vertices.

思路

我們定義我的樹為 \(A\) ,對方的樹為 \(B\) ,如下圖所示:

我們先取 \(B\) 樹中選了的其中一個點,假設為 \(a\),詢問它在 \(A\)中的編號,記為 \(b\)

假如 \(b\) 就是 \(A\)選了的點,輸出 \(b\) 即可。

否則,在 \(A\) 中以 \(a\) 為根,則 \(A\)選了的 點應如藍色區域所示,對應 \(B\) 樹中應為黃色區域

藍色區域\(c\) 點,詢問其在 \(B\)對應的點 \(d\)。因為選的點是連通塊,所以 \(B\) 中選了的點必然為紅色區域,此時只需判斷 \(d\) 是否為 \(B\)選中的點即可。

每組資料詢問次數兩次,總時間複雜度 \(O(nT)\)

Code

// Problem: CF1044B Intersecting Subtrees
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1044B
// Memory Limit: 250 MB
// Time Limit: 2000 ms

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define N 10010
//#define M
//#define mo
struct node
{
	int x, y, n; 
}d[N<<1]; 
int n, m, i, j, k, T; 
int h[N], mx[N], my[N]; 
int a[N], b[N]; 
int u, v, x, y, k1, k2; 

void init()
{
	memset(h, 0, sizeof(h)); 
	memset(d, 0, sizeof(d)); 
	memset(mx, 0, sizeof(mx)); 
	memset(my, 0, sizeof(my)); 
	k=0; 
}

void cun(int x, int y)
{
	d[++k].x=x; d[k].y=y; 
	d[k].n=h[x]; h[x]=k; 
}

int dfs(int x, int fa)
{
	int g, y, z; 
	for(g=h[x]; g; g=d[g].n)
	{
		y=d[g].y; 
		if(y==fa) continue; 
		if(mx[y]) return y; 
		z=dfs(y, x); 
		if(z) return z; 
	}
	return 0; 
}

signed main()
{
//	freopen("tiaoshi.in","r",stdin);
//	freopen("tiaoshi.out","w",stdout);
	T=read(); 
	while(T--)
	{
		n=read(); init(); 
		for(i=1; i<n; ++i)
			u=read(), v=read(), cun(u, v), cun(v, u); 
		k1=read(); for(i=1; i<=k1; ++i) mx[a[i]=read()]=1; 
		k2=read(); for(i=1; i<=k2; ++i) my[b[i]=read()]=1; 
		printf("B %d\n", b[1]); 
		fflush(stdout); 
		cin>>x; if(x==-1) break; 
		// printf("%d\n", x); 
		if(mx[x]) printf("C %d\n", x), fflush(stdout); 
		else
		{
			y=dfs(x, 0); 
			printf("A %d\n", y); 
			fflush(stdout); 
			cin>>x; if(x==-1) break; 
			printf("C %d\n", (my[x] ? y : -1)); 
			fflush(stdout); 
		}
	}
	return 0;
}