题目链接
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;
}