给你一颗大小为n<=1e5的树,三种颜色,每个点涂一种颜色,相邻点不能同色。下面告诉你一些点已经被涂色,并
且告诉你是哪一种颜色,问你涂完整棵树有多少种方法?mod 1e9+7。
考虑树上dp,设(f_{u,i})表示以u为根的子树中,u被染成i这个颜色的方案数,于是考虑状态转移方程
如果这个点被指定染色了,那么有
[f_{u,c_u}=prod_{vin son(u)}sum_{i=1}^3 f_{v,i} (i
e c_u)
]
因为假如u选了一个颜色,那么它的每个儿子都只能有两种颜色可选,先用加法原理统计儿子可选的颜色,然后再用乘法原理统计这棵子树的答案
然后可以得出未被指定颜色点的方程
[egin{cases}f_{u,1}=prod_{vin son(u)} (f_{v,2}+f_{v,3})\f_{u,2}=prod_{vin son(u)} (f_{v,1}+f_{v,3})\f_{u,3}=prod_{vin son(u)} (f_{v,1}+f_{v,2})
end{cases}]
这样就做完了QAQ
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
const int N = 1e5;
const int p = 1e9 + 7;
using namespace std;
int n,k,c[N + 5],f[N + 5][4];
vector <int> d[N + 5];
void dfs(int u,int fa)
{
vector <int>::iterator it;
int sum[4] = {1,1,1,1};
for (it = d[u].begin();it != d[u].end();it++)
{
int v = (*it);
if (v == fa)
continue;
dfs(v,u);
if (c[u])
{
int s = 0;
for (int i = 1;i <= 3;i++)
if (i != c[u])
s = (s + f[v][i]) % p;
sum[c[u]] = 1ll * sum[c[u]] * s % p;
}
else
for (int i = 1;i <= 3;i++)
{
int s = 0;
for (int j = 1;j <= 3;j++)
if (i != j)
s = (s + f[v][j]) % p;
sum[i] = 1ll * sum[i] * s % p;
}
}
if (c[u])
f[u][c[u]] = sum[c[u]];
else
for (int i = 1;i <= 3;i++)
f[u][i] = sum[i];
}
int main()
{
scanf("%d%d",&n,&k);
int u,v;
for (int i = 1;i < n;i++)
{
scanf("%d%d",&u,&v);
d[u].push_back(v);
d[v].push_back(u);
}
for (int i = 1;i <= k;i++)
{
scanf("%d%d",&u,&v);
c[u] = v;
}
dfs(1,0);
cout<<((f[1][1] + f[1][2]) % p + f[1][3]) % p<<endl;
return 0;
}