AT_dp_v Subtree题解
题目描述
有一棵包含 N 个顶点的树。顶点编号为 1,2,…,N。对于每个 i(1≤i≤N−1),第 i 条边连接顶点 xi 和 yi。
太郎君打算将每个顶点涂成白色或黑色。此时,需要保证任意两个黑色顶点之间,都可以仅通过黑色顶点相互到达。
给定一个正整数 M。对于每个 v(1≤v≤N),请回答以下问题:
- 以顶点 v 为黑色的所有顶点染色方案有多少种?请输出对 M 取模的结果。
输入格式
输入以如下格式从标准输入读入。
N M
x1 y1
x2 y2
⋮
xN−1 yN−1
输出格式
输出 N 行。对于每个 v(1≤v≤N),第 v 行输出以下问题的答案:
- 以顶点 v 为黑色的所有顶点染色方案有多少种?请输出对 M 取模的结果。
显示翻译
题意翻译
输入输出样例
输入 #1复制
3 100 1 2 2 3
输出 #1复制
3 4 3
输入 #2复制
4 100 1 2 1 3 1 4
输出 #2复制
8 5 5 5
输入 #3复制
1 100
输出 #3复制
1
输入 #4复制
10 2 8 5 10 8 6 5 1 5 4 8 2 10 3 6 9 2 1 7
输出 #4复制
0 0 1 1 1 0 1 0 1 1
说明/提示
限制条件
- 所有输入均为整数。
- 1≤N≤105
- 2≤M≤109
- 1≤xi,yi≤N
- 给定的图为一棵树。
样例解释 1
顶点染色的方案共有 7 种。在这些方案中,顶点 1 为黑色的有 3 种,顶点 2 为黑色的有 4 种,顶点 3 为黑色的有 3 种。

样例解释 4
不要忘记输出答案对 M 取模的结果。
由 ChatGPT 4.1 翻译
思路
树形DP。
代码见下
#include<bits/stdc++.h>
using namespace std;
long long n,m,u,vv,f[100005],g[100005];
vector<long long> v[100005];
vector<long long> qq[100005];
vector<long long> hh[100005];
void abc(long long a1,long long b1){
f[a1]=1;
for(int i=0;i<v[a1].size();i++){
long long tt=v[a1][i];
if(tt!=b1){
abc(tt,a1);
f[a1]=f[a1]*(f[tt]+1)%m;
qq[a1].push_back(f[tt]+1);
hh[a1].push_back(f[tt]+1);
}
}
for(int i=1;i<qq[a1].size();i++){
qq[a1][i]=qq[a1][i]*qq[a1][i-1]%m;
}
for(int i=hh[a1].size()-2;i>=0;i--){
hh[a1][i]=hh[a1][i]*hh[a1][i+1]%m;
}
return ;
}
void abc2(long long a1,long long b1){
long long f1=0,f2=qq[a1].size();
for(int i=0;i<v[a1].size();i++){
long long tt=v[a1][i];
if(tt!=b1){
f1++;
if(f2==1){
g[tt]=g[a1]+1;
}
else if(f1==1){
g[tt]=g[a1]*hh[a1][f1]%m+1;
}
else if(f1==f2){
g[tt]=g[a1]*qq[a1][f1-2]%m+1;
}
else{
g[tt]=g[a1]*(qq[a1][f1-2]*hh[a1][f1]%m)%m+1;
}
abc2(tt,a1);
}
}
return ;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n-1;i++){
cin>>u>>vv;
v[u].push_back(vv);
v[vv].push_back(u);
}
abc(1,0);
g[1]=1;
abc2(1,0);
for(int i=1;i<=n;i++){
cout<<f[i]*g[i]%m<<endl;
}
return 0;
}

浙公网安备 33010602011771号