「杂题乱刷2」CF1738F Connectivity Addicts

题目链接

CF1738F Connectivity Addicts

解题思路

我们发现取度数大的点可以建的图显然最优秀,具体原因下面会讲,并且同一个连通块内的节点染成一种颜色一定合法。那么此时我们将所有节点从大到小排序,然后直接暴力建图即可,我们每次询问会存在两种情况,我们设询问到的节点为 \(x\)

  • \(x\) 已经被染上颜色了,那么直接将此节点与 \(x\) 节点连边,退出此节点查询。

  • \(x\) 没有被染上颜色,那么直接将此节点与 \(x\) 节点连边,继续进行此节点的查询。

那么此时由于度数是从大到小连边,此时必定有 \(s_c \le d_c^2\),因为此时点已经与 \(s_c\) 个节点连边,此时设询问的节点为 \(x\)\(i\) 与为 \(x\) 连通的点,设 \(d_x\) 为节点 \(x\) 的度数,由于是从大到小枚举的,那么此时一定有 \(d_i \le d_x\),而连入的点可能会变多,但绝不会变小,若新连入的点为 \(y\),则也必有 \(d_y \le d_x\),此时根据完全平方公式可知原条件一定仍满足,因此该构造方式是正确的。

参考代码

ll ask(ll x)
{
    cout<<"? "<<x<<endl;
    ll y;
    cin>>y;
    return y;
}
ll n;
pii a[1000010];
ll col[1000010];
ll id;
void solve()
{
    id=0;
    cin>>n;
    forl(i,0,n+5)
        col[i]=0;
    forl(i,1,n)
        cin>>a[i].x,
        a[i].y=i;
    sort(a+1,a+1+n);
    reverse(a+1,a+1+n);
    forl(i,1,n)
        if(!col[a[i].y])
        {
            vector<ll>v;
            ll num=0;
            forl(j,1,a[i].x)
            {
                num=ask(a[i].y);
                v.pb(num);
                if(col[num])
                    break;
            }
            ll Col=col[num]?col[num]:++id;
            col[a[i].y]=Col;
            for(auto j:v)
                col[j]=Col;
        }
    cout<<"! ";
    forl(i,1,n)
        cout<<col[i]<<' ';
    cout<<endl;
}
posted @ 2025-02-13 23:02  wangmarui  阅读(10)  评论(0)    收藏  举报