zoukankan      html  css  js  c++  java
  • CF1492D Hemose in ICPC ?

    传送门


    这似乎是我在cf上做的第一道交互题。


    题本身不难,给一棵(n)个节点、边权未知的树,定义两个节点之间的距离为路径上所有边权的gcd。每次你可以询问一个节点集合,然后交互程序会返回所给集合中最大的距离,求在不超过12次询问的前提下,距离最大的两个节点的编号。


    比赛的时候卡c了,d就没怎么看。今天再看这题的时候想到了一个类似点分治的做法。

    首先显而易见的是,最终答案一定是一条边,而不是某个路径。然后我就想不断找树的“重边”(删去这条边后两部分的最大值最小),然后询问其中一半,如果最大值出现在这一半,就递归到这一半,否则去另一半递归。

    但题解给了一个更简单的做法:先求出这棵树的欧拉序列(每个节点记录入栈和出栈),这样这个序列有一个性质,即每个子区间中的节点一定是相连的。因此我们就可以仿照上面的思路直接在这个序列上进行二分,直到区间大小为2。

    时间复杂度(O(nlog n)),所需要的的询问次数是(1+log(2n-1))(按我的代码的写法,欧拉序列的长度是(sum_{i=1}^n (son[i] + 1)=n + sum_{i=1}^n son[i] = n + n - 1 = 2n - 1)

    #include<bits/stdc++.h>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e3 + 5;
    const int maxt = 1e6 + 5;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    In void MYFILE()
    {
    #ifndef mrclr
    	freopen(".in", "r", stdin);
    	freopen(".out", "w", stdout);
    #endif
    }
    
    int n;
    struct Edge
    {
    	int nxt, to;
    }e[maxn << 1];
    int head[maxn], ecnt = -1;
    In void addEdge(int x, int y)
    {
    	e[++ecnt] = (Edge){head[x], y};
    	head[x] = ecnt;
    }
    
    int dfn[maxt], cnt = 0;
    In void dfs(int now, int _f)
    {
    	dfn[++cnt] = now;
    	forE(i, now, v)
    	{
    		if(v == _f) continue;
    		dfs(v, now);
    		dfn[++cnt] = now; 
    	}
    }
    
    bool vis[maxn];
    In int query(int L, int R)
    {
    	int sum = 0;
    	for(int i = L; i <= R; ++i)
    		if(!vis[dfn[i]]) ++sum, vis[dfn[i]] = 1;
    	putchar('?'), space, write(sum), space;
    	for(int i = L; i <= R; ++i) if(vis[dfn[i]]) write(dfn[i]), space, vis[dfn[i]] = 0;
    	enter;
    	fflush(stdout);
    	return read();
    }
    
    int main()
    {
    //	MYFILE();
    	Mem(head, -1), ecnt = -1;
    	n = read(); 
    	for(int i = 1; i < n; ++i)
    	{
    		int x = read(), y = read();
    		addEdge(x, y), addEdge(y, x);
    	}
    	dfs(1, 0);
    	int Max = query(1, cnt), L = 1, R = cnt;
    	while(R - L > 1)
    	{
    		int mid = (L + R) >> 1;
    		int x = query(L, mid);
    		if(x == Max) R = mid;
    		else L = mid;
    	}
    	putchar('!'), space, write(dfn[L]), space, write(dfn[R]), enter;
    	return 0;
    }
    
  • 相关阅读:
    JS BOM对象 History对象 Location对象
    JS 字符串对象 数组对象 函数对象 函数作用域
    JS 引入方式 基本数据类型 运算符 控制语句 循环 异常
    Pycharm Html CSS JS 快捷方式创建元素
    CSS 内外边距 float positio属性
    CSS 颜色 字体 背景 文本 边框 列表 display属性
    【Android】RxJava的使用(三)转换——map、flatMap
    【Android】RxJava的使用(二)Action
    【Android】RxJava的使用(一)基本用法
    【Android】Retrofit 2.0 的使用
  • 原文地址:https://www.cnblogs.com/mrclr/p/15374315.html
Copyright © 2011-2022 走看看