zoukankan      html  css  js  c++  java
  • [CF1370F2]The Hidden Pair (Hard Version)

    题目

    点这里看题目。

    分析

    第一道交互题,真好玩。

    我们以下就称 (a,b) 为选定的两个点。

    不难想到一个大致思路:首先,找出一个在 ((a,b)) 上的一个点。然后找出 (a) 或者 (b) 中的一个点。此时我们必然知道 ((a,b)) 的长度,因此我们可以再用一次询问获得另一个点。

    为了达成第一步,我们可以直接将所有点丢到询问里面查一遍。现在我们设得到了点 (x) ,且知道了路径长度为 (l)

    考虑将树旋转到以 (x) 为根。现在我们需要找出 (a)(b) 中的一个点。数据范围明示二分。并且不难发现,如果我们将同一深度的所有点进行查询,那么查询的结果 (d) 按照深度递增而递增。

    (d) 变大是因为不存在一个点在 ((a,b)) 上了。因此,我们可以通过二分查询到 (a,b) 中较深的一个点。接着进行第三步,我们就可以得到 (a)(b)

    但是此时的查询次数是 (1+lceillog_2n ceil+1=12) 。我们需要再优化掉一次查询。
    注意到 (a,b) 两个点的较大深度的点的深度,一定 (ge lceilfrac l 2 ceil) 。因此我们将二分的范围设成 (lceilfrac l 2 ceil) ,就可以少一次查询,通过本题。

    小结:

    1. 本题中的优化查询次数的方法比较有借鉴意义。虽然传统题基本不可能卡你这种东西......

    代码

    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <cstdlib>
    #include <utility>
    using namespace std;
    
    typedef pair<int, int> Info;
    
    const int MAXN = 1005, MAXLOG = 10;
    
    template<typename _T>
    void read( _T &x )
    {
        x = 0;char s = getchar();int f = 1;
        while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
        while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
        x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
        if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
        if( 9 < x ){ write( x / 10 ); }
        putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    _T MIN( const _T a, const _T b )
    {
        return a < b ? a : b;
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
        return a > b ? a : b;
    }
    
    struct Edge
    {
        int to, nxt;
    }Graph[MAXN << 1];
    
    vector<int> pnt[MAXN];
    
    int head[MAXN], dep[MAXN];
    int N, cnt, mxdep;
    
    void AddEdge( const int from, const int to )
    {
        Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
        head[from] = cnt;
    }
    
    void Clean()
    {
        mxdep = cnt = 0;
        for( int i = 0 ; i <= N ; i ++ )
            pnt[i].clear(), head[i] = 0;
    }
    
    void DFS( const int u, const int fa )
    {
        pnt[dep[u] = dep[fa] + 1].push_back( u );
        for( int i = head[u], v ; i ; i = Graph[i].nxt )
            if( ( v = Graph[i].to ) ^ fa )
                DFS( v, u );
        mxdep = MAX( mxdep, dep[u] );
    }
    
    namespace API
    {
        Info Ask( vector<int> num, const int aband = 0 )
        {
            printf( "? %d", num.size() );
            for( int i = 0 ; i < ( int ) num.size() ; i ++ )
                if( num[i] ^ aband )
                    putchar( ' ' ), write( num[i] );
            putchar( '
    ' ), fflush( stdout );
            
            Info ret; 
            read( ret.first ), read( ret.second );
            return ret;
        }
        
        void Answer( const int a, const int b )
        {
            printf( "! %d %d
    ", a, b ); 
            fflush( stdout );
            char ret[100]; scanf( "%s", ret );
            if( ! strcmp( ret, "Incorrect" ) ) exit( 0 );
        }
    }
    
    int main()
    {
        int T;
        read( T );
        while( T -- )
        {
            read( N ), Clean();
            for( int i = 1, a, b ; i < N ; i ++ ) 
                read( a ), read( b ), AddEdge( a, b ), AddEdge( b, a );
            
            vector<int> all; all.clear();
            for( int i = 1 ; i <= N ; i ++ ) all.push_back( i );
            Info fir = API :: Ask( all ), lst, tmp;
            int cur = fir.first, d = fir.second;
            
            dep[0] = -1, DFS( cur, 0 );
            int l = MIN( ( d - 1 >> 1 ) + 1, mxdep ), r = MIN( d, mxdep ), mid;
            
            while( l <= r )
            {
                mid = l + r >> 1;
                if( ( tmp = API :: Ask( pnt[mid] ) ).second > d ) r = mid - 1;
                else l = mid + 1, lst = tmp;
            }
            
            all.clear();
            int x = lst.first; DFS( x, 0 );
            for( int i = 1 ; i <= N ; i ++ )
                if( dep[i] == d ) all.push_back( i );
            int y = API :: Ask( all ).first;
            
            API :: Answer( x, y );
        }
        return 0;
    }
    
  • 相关阅读:
    设计模式的原则和法则
    GoF的23种设计模式分类和功能
    2020年智慧电力解决方案
    【转载】「黑科技」智能防疫消毒机器人 技术方案介绍-disinfection robot
    【转载】如何让电力巡检机器人项目落地
    30多张图来了解Keil5的使用
    [数学学习与代码]最小二乘法--多元线性方程求解
    MTK-LCM 屏幕使用fbconfig/PanelMaster来调试LCM驱动
    MTK 使用iptable 命令来完成网络路由(android WIFI/4G分享网络)
    MTK(android init.rc) 写一个开机启动的服务
  • 原文地址:https://www.cnblogs.com/crashed/p/13712955.html
Copyright © 2011-2022 走看看