## [USACO17DEC]Barn Painting

### 题目概况

#### 题目描述

Farmer John has a large farm with $$N$$ barns ($$1 \le N \le 10^5$$), some of which are already painted and some not yet painted. Farmer John wants to paint these remaining barns so that all the barns are painted, but he only has three paint colors available. Moreover, his prize cow Bessie becomes confused if two barns that are directly reachable from one another are the same color, so he wants to make sure this situation does not happen. It is guaranteed that the connections between the $$N$$ barns do not form any 'cycles'. That is, between any two barns, there is at most one sequence of connections that will lead from one to the other. How many ways can Farmer John paint the remaining yet-uncolored barns?

#### 输入输出格式

##### 输入格式

The first line contains two integers $$N$$ and $$K$$ ($$0 \le K \le N$$), respectively the number of barns on the farm and the number of barns that have already been painted. The next $$N-1$$ lines each contain two integers $$x$$ and $$y$$ ($$1 \le x, y \le N, x \neq y$$) describing a path directly connecting barns $$x$$ and $$y$$. The next $$K$$ lines each contain two integers $$b$$ and $$c$$ ($$1 \le b \le N$$, $$1 \le c \le 3$$) indicating that barn $$b$$ is painted with color $$c$$.

##### 输出格式

Compute the number of valid ways to paint the remaining barns, modulo $$10^9 + 7$$, such that no two barns which are directly connected are the same color.

#### 输入输出样例

##### 输入样例 #1
4 1
1 2
1 3
1 4
4 3
##### 输出样例 #1
8

### 解题报告

#### 题意解析

1. 给定一颗$$N$$个节点组成的树
2. 每个节点上可以$$3$$种颜色
3. 其中K个节点染色
4. 要求任意两相邻节点颜色不同，求合法染色方案数。

#### 算法解析

1. 一棵树，且树的节点很多
2. 上下关系明显，要求颜色不同
3. 统计合法方案数量

$f[i][j]，i节点，染色为j，节点i为根的合法方案数量$

1. 上下颜色不同
2. 有些点颜色固定

$f[i][1]=f[i][1] \times (f[y1][2]+f[y1][3]) \quad y1是x的儿子节点$

1. 乘法原理，所以是各个儿子方案乘积
2. 儿子的颜色不等于父亲颜色，但是儿子之间颜色没有限制

$f[i][1]= \prod(f[y][2]+f[y][3]) \\\\ f[i][2]= \prod(f[y][1]+f[y][3]) \\\\ f[i][3]= \prod(f[y][1]+f[y][2]) \\\\ y为i的儿子节点$

$若i节点颜色为1 \Rightarrow f[i][2]=f[i][3]=0,f[i][1]=1 \\ 其他同理，只不过修改j的问题而言$

#### 代码解析

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+20,Mod=1e9+7;
int n,a[N],k,c[N],x,y;
long long f[N][4];
vector<int> g[N];
inline void Dp(int x,int s)//s为x父亲节点
{
if (c[x])//颜色限制
f[x][c[x]]=1;
else
f[x][1]=f[x][2]=f[x][3]=1;
for(int y:g[x])
{
if (y==s)
continue;
Dp(y,x);
f[x][1]=f[x][1]*(f[y][2]+f[y][3])%Mod;//当前元素为k,则儿子的颜色不为k
f[x][2]=f[x][2]*(f[y][1]+f[y][3])%Mod;//因此这个儿子,提供的方案数就为另外两种颜色的之和
f[x][3]=f[x][3]*(f[y][1]+f[y][2])%Mod;//根据乘法定理,所有儿子的乘积就是我们所谓的当前节点的方案数
}
}
inline void init()
{
scanf("%d%d",&n,&k);
for(int i=1; i<n; i++)
{
scanf("%d%d",&x,&y);
g[x].push_back(y),g[y].push_back(x);
}
for (int i=1; i<=k; i++)
{
scanf("%d%d",&x,&y);
c[x]=y;
}
Dp(1,0);
printf("%lld\n",(f[1][1]+f[1][2]+f[1][3])%Mod);
}
signed main()
{
init();
return 0;
}