1. 程式人生 > 其它 >CF1244D Paint the Tree 題解

CF1244D Paint the Tree 題解

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