• [CSAcademy]Find the Tree


    [CSAcademy]Find the Tree

    题目大意:

    交互题。

    有一棵(n(nle2000))个结点的树,但是你并不知道树的形态。你可以调用({ m query}(x,y,z))(其中(x,y,z)互不相同)得到与(x,y,z)三点距离之和最小的点(t)。要求你使用不超过(25000)次询问,求出树上的所有边。

    保证树的形态随机。

    思路:

    一开始先随便找两个点(x,y),枚举第三个点(z),询问({ m query}(x,y,z)),则返回的(t)一定是(x,y)链上的点,而枚举完所有的(z)后,链上的所有点都能被找出来。

    对于链上的点(c_1,c_2),若({ m query}(x,c_1,c_2)=c_1),则(c_1)更靠近(x),否则(c_2)更靠近(x)。这样,我们可以对链上结点排序,从而求出链上的每一条边。

    而在上述询问的过程中,我们也可以顺便求出去掉链(x,y)后,每个结点(z)在哪个子树中。对每一个子树递归进行上述操作即可。

    据说可以证明重心落在随机链上的概率(>frac12),因此总的询问次数大约是(mathcal O(nlog n))的。

    源代码:

    #include<set>
    #include<ctime>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstdlib>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=2001;
    std::vector<int> v[N];
    std::vector<std::pair<int,int>> ans;
    inline int query(const int &x,const int &y,const int &z) {
    	if(x==y) return x;
    	if(x==z) return x;
    	if(y==z) return y;
    	printf("Q %d %d %d
    ",x,y,z);
    	fflush(stdout);
    	return getint();
    }
    void solve(const int &x) {
    	if(v[x].empty()) return;
    	std::vector<int> u;
    	u.swap(v[x]);
    	const int &y=u[rand()%u.size()];
    	std::set<int> set;
    	set.insert(x);
    	set.insert(y);
    	for(register unsigned i=0;i<u.size();i++) {
    		const int &z=u[i];
    		if(z==y) continue;
    		const int t=query(x,y,z);
    		set.insert(t);
    		if(t!=z) v[t].push_back(z);
    	}
    	std::vector<int> chain(set.begin(),set.end());
    	std::sort(chain.begin(),chain.end(),
    		[x](const int &y,const int &z) {
    			return query(x,y,z)==y;
    		}
    	);
    	for(register unsigned i=1;i<chain.size();i++) {
    		ans.emplace_back(chain[i-1],chain[i]);
    	}
    	for(int v:chain) solve(v);
    }
    int main() {
        srand(time(NULL));
    	const int n=getint();
    	for(register int i=2;i<=n;i++) {
    		v[1].push_back(i);
    	}
    	solve(1);
    	puts("A");
    	for(auto e:ans) {
    		printf("%d %d
    ",e.first,e.second);
    	}
    	return 0;
    }
    
  • 相关阅读:
    引用kernel32.dll中的API来进行串口通讯
    vs2017 项目生成时不产生xml文件的方法
    session的处理机制
    用户未登录或Session超时时重定向到登录页,不那么简单
    VS C# debug文件夹中各文件的作用
    Tomcat(免安装版)的安装与配置【转】
    关于C#关闭窗体后,依旧有后台进程在运行的解决方法
    DatakeyNames和datakey
    ASP.NET页面生命周期描述
    比较C#中几种常见的复制字节数组方法的效率
  • 原文地址:https://www.cnblogs.com/skylee03/p/10572379.html
Copyright © 2020-2023  润新知