题目要求将树分为k个部分,并且每种颜色恰好在同一个部分内,问有多少种方案。

第一步显然我们需要知道哪些点一定是要在一个部分内的,也就是说要求每一个最小的将所有颜色i的点连通的子树。

这一步我们可以将所有有颜色的点丢入优先队列,然后另深度最深的点优先出队。

如果此时这个点的颜色有不只一个点在队列中,那么我们必须要考虑将它的父亲染色,这样才能与其他的该颜色的点连通。

此时有3种情况:

1.如果它的父亲已经被染色且颜色与该点不同,那么此时显然无解;

2.如果它的父亲与它颜色相同,那么此时不做任何操作。

3.如果它的父亲无色,那么将其染色并入队。

经过这样的一番操作后我们已经将必须染色的点染色,那么现在方案数就来自与现在仍然无色的点。

第二步,方案数可以用树形dp来求得。

我们将每个点分为两种状态,记dp[now][0]为点now已经确定颜色的方案数,dp[now][1]为未确定颜色的方案数。

接下来分类讨论如何求这两个状态的dp值:

1.如果这个点原本就有颜色

  那么此时显然dp[now][1]=0,dp[now][0]=所有子节点i的(dp[i][0]+dp[i][1])的乘积,因为如果子节点已经染色,那显然状态可以继承,如果未染色,那么显然此时必须被点now染色。

2.如果这个点未被染色

  此时的dp[now][1]就等于情况1的dp[now][0],而dp[now][0]则要在所有子节点中选择一个子节点,令点now被这个子节点i染色,那首先前提显然是i节点已经确定颜色,所以此时枚举每个子节点,

对dp[i][0]*dp[now][1]/(dp[i][0]+dp[i][1])求和。

以下为代码:

#include<bits/stdc++.h>
using namespace std;
const long long mod=998244353;
int i,i0,n,m,k,col[300005],dep[300005],fa[300005],cnt[300005];
vector<int>mp[300005];
void dfs(int now,int d)
{
dep[now]=d;
for(int i:mp[now])if(!dep[i])dfs(i,d+1),fa[i]=now;
return;
}
struct node
{
int x,d;
bool operator<(node a)const{return d<a.d;}
};
priority_queue<node>q;
long long dp[300005][2];
void extgcd(long long a,long long b,long long& d,long long& x,long long& y)
{
if(!b){d=a;x=1;y=0;}
else{extgcd(b,a%b,d,y,x);y-=x*(a/b);}
}
long long inv(long long a,long long n)
{
long long d,x,y;
extgcd(a,n,d,x,y);
return d==1?(x+n)%n:-1;
}
void dfs0(int now)
{
dp[now][0]=dp[now][1]=1;
for(auto i:mp[now])
{
if(i==fa[now])continue;
dfs0(i);
dp[now][1]*=(dp[i][0]+dp[i][1]);
dp[now][1]%=mod;
}
if(col[now])
{
dp[now][0]=dp[now][1];
dp[now][1]=0;
}
if(!col[now])
{
dp[now][0]=0;
for(auto i:mp[now])
{
if(i==fa[now])continue;
dp[now][0]+=dp[now][1]*inv(dp[i][0]+dp[i][1],mod)%mod*dp[i][0]%mod;
dp[now][0]%=mod;
}
}
return;
}
int main()
{
scanf("%d %d",&n,&k);
for(i=1;i<=n;i++)scanf("%d",&col[i]),cnt[col[i]]++;
for(i=1;i<n;i++)
{
int x,y;
scanf("%d %d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
dfs(1,1);
for(i=1;i<=n;i++)if(col[i])q.push({i,dep[i]});
while(!q.empty())
{
node tmp=q.top();
q.pop();
if(col[fa[tmp.x]]==col[tmp.x])cnt[col[tmp.x]]--;
else
{
if(cnt[col[tmp.x]]!=1)
{
if(!col[fa[tmp.x]])
{
col[fa[tmp.x]]=col[tmp.x];
q.push({fa[tmp.x],dep[fa[tmp.x]]});
}
else
{
printf("0\n");
return 0;
}
}
}
}
dfs0(1);
printf("%lld\n",dp[1][0]);
return 0;
}

Codeforces 1118 F2. Tree Cutting (Hard Version) 优先队列+树形dp的更多相关文章

  1. CodeForces - 1118 F2 Tree Cutting

    题目传送门 题解: 先注意到一定存在k种颜色,切成k个块, 然后要求每个块内的颜色都一样,所以可以发现同一种颜色一定在同一个块内,故任意2个相同颜色的最短路劲上的点的颜色都是该颜色. 我们可以先把任意 ...

  2. Codeforces 1118F1 Tree Cutting (Easy Version) (简单树形DP)

    <题目链接> 题目大意: 给定一棵树,树上的点有0,1,2三中情况,0代表该点无色.现在需要你将这棵树割掉一些边,使得割掉每条边分割成的两部分均最多只含有一种颜色的点,即分割后的两部分不能 ...

  3. Tree Cutting POJ - 2378 (树形DP)

    题目链接:POJ - 2378 题目大意:给你n个点,然后问你这n个点中 ,去除哪些点能够使得剩下的图中最大的连通块中点的个数不超过n/2. 具体思路:第一遍dfs记录每一个点代表的子树大小,第二遍d ...

  4. hdu 5909 Tree Cutting——点分治(树形DP转为序列DP)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5909 点分治的话,每次要做一次树形DP:但时间应该是 siz*m2 的.可以用 FWT 变成 siz*ml ...

  5. BZOJ 3391 [Usaco2004 Dec]Tree Cutting网络破坏(树形DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3391 [题目大意] 给定一棵树,求分支size均不大于一半点数的点 [题解] 递归的同 ...

  6. Codeforces Round #540 (Div. 3) F1. Tree Cutting (Easy Version) 【DFS】

    任意门:http://codeforces.com/contest/1118/problem/F1 F1. Tree Cutting (Easy Version) time limit per tes ...

  7. Codeforces 1606F - Tree Queries(虚树+树形 dp)

    Codeforces 题面传送门 & 洛谷题面传送门 显然我们选择删除的点连同 \(u\) 会形成一个连通块,否则我们如果选择不删除不与 \(u\) 在同一连通块中的点,答案一定更优. 注意到 ...

  8. Codeforces 743D:Chloe and pleasant prizes(树形DP)

    http://codeforces.com/problemset/problem/743/D 题意:求最大两个的不相交子树的点权和,如果没有两个不相交子树,那么输出Impossible. 思路:之前好 ...

  9. Codeforces Round #540 (Div. 3)--1118F1 - Tree Cutting (Easy Version)

    https://codeforces.com/contest/1118/problem/F1 #include<bits/stdc++.h> using namespace std; in ...

随机推荐

  1. R语言与.net 集成开发入门

    首先:R语言的基本教程: https://www.yiibai.com/r/r_environment_setup.html 下载R语言的安装包:https://cran.r-project.org/ ...

  2. 使用github搭建个人html网站

    前言:搭建个人网站早就想做了,最近有空就宅在家学习,突然发现github就可以搭建个人的纯html网站,于是开始了这项工作.转载请注明出处:https://www.cnblogs.com/yuxiao ...

  3. CF954F Runner's Problem

    离散化+矩阵快速幂 首先看数据范围可以确定该题的算法为矩阵快速幂 然后易得转移矩阵 \[\begin{bmatrix} 1 & 1 & 0 \\ 1 & 1 & 1 \ ...

  4. jQuery基础(Ajax,load(),getJSON(),getScript(),post(),ajax(),同步/异步请求数据)

    1.使用load()方法异步请求数据   使用load()方法通过Ajax请求加载服务器中的数据,并把返回的数据放置到指定的元素中,它的调用格式为:   load(url,[data],[callba ...

  5. dnspod域名解析设置

    time: 2016-01-8 10:30     因为我的博客是用Github page搭建的,所以要把域名和Github_name.github.io的URL联系起来.本人实在小白一个,就纪录一下 ...

  6. RollViewPager图片轮播效果开源框架的使用

    RollViewPager是一个自动轮播的Viewpager, 支持无限循环. 触摸时会暂停播放,直到结束触摸一个延迟周期以后继续播放. 看起来就像这样.指示器可以为点可以为数字还可以自定义,位置也可 ...

  7. Android ListView几个重要属性

    1.transciptMode属性,需要用ListView或者其它显示大量Items的控件实时跟踪或者查看信息,并且希望最新的条目可以自动滚动到可视范围内.通过设置的控件transcriptMode属 ...

  8. linux 软件包 rpm命令之安装、更新、卸载、依赖

    软件包分类1.源码包2.二进制包二进制包是源码包编译后产生的文件..exe文件是适用于windows平台的二进制包:RPM包适用于redhat系列的二进制包:deb包是适用于ubuntu平台的二进制包 ...

  9. oracle 和 mysql 和区别

    1.mysql 有枚举类型,oracle 没有; mysql不支持number.varchar2类型,报错.2.oracle 支持全外连接,mysql 不支持 select e.ename, e.sa ...

  10. 类和类的关系——java

    类(对象)之间的关系   1.继承关系(子类自动拥有了父类所有的成员变量和普通方法,如果父类的成员变量和普通方法是private 的,那么子类只有拥有权,没有使用权.父类的构造方法在子类的构造方法执行 ...