CF1244D Paint the Tree
思路:
这道题的翻译害人不浅,我一直以为是三个节点都相同才不能选,结果看了看英文题面,是三个中两两互不相同。
那么根据抽屉原理,当点 i 的入度 $in_i \ge 3$ 的时候,无论怎么取,四个点必有两个相同,无解。
若有解,则必然满足 $in_i \le 2(i \in [1,n])$,即题中的树是一条链。
那么情况就很简单了,枚举一下链头的两个节点颜色,剩下的点自然就推出来了,所有答案统计一下比较出最小值即可。
时间复杂度 $O(N)$。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1e5 + 5; int n,rt,vertex[maxn]; int in[maxn],c[maxn][4],head[maxn],ver[maxn << 1],nxt[maxn << 1],cnt; typedef long long ll; ll ans = 0,tot = 0; int a[maxn],w[maxn]; void add(int u,int v) { ver[++ cnt] = v; nxt[cnt] = head[u]; head[u] = cnt; return ; } void DFS(int u,int fa) { for(int i = head[u];i;i = nxt[i]) { int v = ver[i]; if(v == fa)continue ; DFS(vertex[u] = v , u); } return ; } int main() { scanf("%d",&n); for(int i = 1;i <= 3;++ i) { for(int j = 1;j <= n;++ j) { scanf("%d",&c[j][i]); } } for(int i = 1;i < n;++ i) { int u,v; scanf("%d%d",&u,&v); add(u , v); add(v , u); ++ in[u]; ++ in[v]; } for(int i = 1;i <= n;++ i) { if(in[i] >= 3) { puts("-1"); return 0; } if(in[i] == 1)rt = i; } DFS(rt , 0); int Next = vertex[rt]; ans = 1e16,tot = 0; for(int i = 1;i <= 3;++ i) { for(int j = 1;j <= 3;++ j) { if(!(i ^ j))continue ; tot = c[rt][i] + c[Next][j]; memset(w , 0 , sizeof(w)); int x = Next,y = rt; w[rt] = i; w[Next] = j; while(in[x] > 1) { w[vertex[x]] = w[x] ^ w[y]; tot += c[vertex[x]][w[vertex[x]]]; y = x; x = vertex[x]; } if(ans > tot) { for(int i = 1;i <= n;++ i)a[i] = w[i]; ans = tot; } } } printf("%lld\n",ans); for(int i = 1;i <= n;++ i)printf("%d ",a[i]); return 0; }QAQ