题意:
给出n个点的树,每个点可以有一个权值,然后a和b互通的条件是a^b<=min(a,b),然后两个人一人操作一次,如何构造使得后手胜利的次数多。输就是到我了但是没法走了。
思考:
就是如何狗仔,是的数上面任意两点是不互通的,可以对整个树进行二分图染色,然后对两个点集分配权值,想要两点不通,那么a^b>min(a,b)意思就是,a和b的最高位不同,所以先把每个数的最高位0和1进行分类,然后再去赋值。
代码:
int T,n,m;
int va[N];
int cnt0,cnt1;
int col[N],num[N],anw[N];
vector<int > e[N];
void dfs(int now,int p,int c)
{
col[now] = c;
if(c) cnt1++;
else cnt0++;
for(auto spot:e[now])
{
if(spot==p) continue;
dfs(spot,now,c^1);
}
}
signed main()
{
IOS;
cin>>T;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
e[i].clear();
col[i] = num[i] = anw[i] = 0;
}
for(int i=1;i<n;i++)
{
int a,b;
cin>>a>>b;
e[a].pb(b);
e[b].pb(a);
}
cnt0 = cnt1 = 0;
dfs(1,0,0);
if(cnt0>cnt1) //这里让0颜色成为少数是因为,数最高位为0的还是多的,为1的少,因为0颜色需要1的权值,所以尽量让0颜色少
{
swap(cnt0,cnt1);
for(int i=1;i<=n;i++) col[i] ^= 1;
}
for(int i=1;i<=n;i++)
{
int now = 30;
while(now--)
{
if(i&(1<<now))
break;
}
if(cnt0&(1<<now)) num[i] = 0;
else num[i] = 1;
}
int sum0 = 1,sum1 = 1;
for(int i=1;i<=n;i++)
{
if(col[i]==0)
{
while(num[sum0]==1) sum0++;
anw[i] = sum0++;
}
else
{
while(num[sum1]==0) sum1++;
anw[i] = sum1++;
}
}
for(int i=1;i<=n;i++) cout<<anw[i]<<" ";
cout<<"\n";
}
}
总结:
对于这种思考要想想如何去操作,想到分为两个点集然后去染色和赋值。