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;
}

posted @ 2025-10-23 10:35  bz02_2023f2  阅读(2)  评论(0)    收藏  举报  来源