CF2040D题解
CF2040D题解
神奇构造题,感觉自己想到了一丢丢,但是没有往正解的方向去想。
题意
给出一张 \(n\) 个节点的树,从 \(1-2n\) 中最多每个数选一次填到树中,求一种任意两个节点权值之差都不是质数的填数方案。
分析
比赛的时候考虑到了 \(1-2n\) 这个特殊条件,可以考虑只用偶数或者是奇数,假设是只用 \(2,4,6,8...,2n\) 的话,。
首先想到的是奇偶染色,然后分别把 \(2,6,10...(A)\) 和 \(4,8,12..(B)\) 填到不同颜色中。
然后发现这样全是不合法,所以把这种想法叉掉了。。。。
我们发现实际上就可以从这个角度来思考,先考虑给这个树分层,既然刚刚都顺着填的思路是很错误的,那我们反过来,用一个 Meet in
the middle 的思路来进行染色。
也就是根据 bfs 序和层数的奇偶性来进行填充,对于所有奇数层,我们把 \(2,4,6,8..\) 按顺序填进去;对于 所有的偶数层,我们把 \(2n,2n-2,2n-4...\) 按照顺序填进去,这样一定最后填完的时候不会重,并且大体上都是合法的,因为所有的相邻差都是偶数,并且基本上都不是 \(2\)。那么什么地方会是 \(2\) 呢?肯定就是我们最后meet的地方,而且它一定在叶节点,并且只有这一个不合法的地方,我们直接对他进行 \(+-1\) 就可以了。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int T,n;
inline void solve()
{
cin>>n;
vector<int> e[n+2],a(n+1,0),isf(n+1,0);
vector<vector<int>>num(2,vector<int>(n+2,0));
for(int i=1;i<=n;++i)num[0][i]=i<<1,num[1][i]=(n-i+1)<<1;
for(int i=1,u,v;i<n;++i)
{
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
queue<pair<int,int>> q;
int cnt[2]={0,0};
q.push({1,0});
while(q.size())
{
int x=q.front().first,type=q.front().second;
q.pop();
a[x]=num[type][++cnt[type]];
for(auto v:e[x])
{
if(a[v])continue;
isf[x]=1;
q.push({v,type^1});
}
}
for(int i=1;i<=n;++i)
{
if(isf[i])continue;
for(auto v:e[i])
{
if(abs(a[i]-a[v])==2)
{
if(a[i]>a[v])a[i]--;
else a[i]++;
goto OUTPUT;
}
}
}
OUTPUT:;
for(int i=1;i<=n;++i)cout<<a[i]<<' ';
cout<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--)
{
solve();
}
return 0;
}
另一种解
这种奇怪构造应该可乱搞性挺高的,根据starsilk的说法,好像可以特判菊花,然后还是只用偶数,找到一条长度为 \(4\) 的链,然后根据奇偶染色的原理也可以做。
不过我不太懂。
总结
构造题可以先构造出一种大体合法的方案,然后对于不合法的细节进行微调。
本文来自博客园,作者:Hanggoash,转载请注明原文链接:https://www.cnblogs.com/Hanggoash/p/18596346