题面

好题不问Div(这是Div3最后一题,不得不说Mike真是强=。=)

首先同一个颜色的点的LCA要和它们在一个划分出的块里,那么我们先按颜色把所有点到它们的LCA的路径涂色,如果这个过程中出现了重合的颜色则说明无解。

之后问题转化为一个树形DP问题,设$dp[i][0/1]$表示以$i$为根的子树中i是否划入一个有颜色的块的方案数。然后讨论转移:

1.如果i自身没有颜色

①如果i不划入有颜色的块,那么直接继承子树信息,乘法原理统计,$dp[i][0]=\prod_{v∈son_i}(dp[v][0]+dp[v][1])$

②如果i划入有颜色的块,那么对于每一个子树都单独统计一遍划入其中的方案数,$dp[i][1]=\sum_{v∈son_i}dp[v][1]\prod_{w∈son_i\&\&w!=v}(dp[w][0]+dp[w][1])$,维护每个节点子节点的前缀后缀乘积来转移

2.如果i自身有颜色

①如果i不划入有颜色的块,那么......不划入有颜色的块=。=???$dp[i][0]=0$

②如果i划入有颜色的块,同理于1.①

(因为一个睿智错误多调了一个小时

 #include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define vint vector<int>
#define vit vector<int>::iterator
using namespace std;
const int N=,mod=;
int p[N],noww[*N],goal[*N],siz[N];
int anc[N],dep[N],imp[N],top[N],col[N],dp[N][];
int n,k,cnt,t1,t2; vint ve[N];
void Link(int f,int t)
{
noww[++cnt]=p[f];
goal[cnt]=t,p[f]=cnt;
noww[++cnt]=p[t];
goal[cnt]=f,p[t]=cnt;
}
void Add(int &x,int y)
{
x+=y;
if(x>=mod) x-=mod;
}
void Mul(int &x,int y)
{
x=1ll*x*y%mod;
}
void DFS(int nde,int fth,int dth)
{
int tmp=;
siz[nde]=,anc[nde]=fth,dep[nde]=dth;
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=fth)
{
DFS(goal[i],nde,dth+);
siz[nde]+=siz[goal[i]];
if(siz[goal[i]]>tmp)
tmp=siz[goal[i]],imp[nde]=goal[i];
}
}
void Decompose(int nde,int tpp)
{
top[nde]=tpp;
if(imp[nde])
{
Decompose(imp[nde],tpp);
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=anc[nde]&&goal[i]!=imp[nde])
Decompose(goal[i],goal[i]);
}
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y); x=anc[top[x]];
}
return dep[x]<dep[y]?x:y;
}
void Climb(int nde,int lca,int cor)
{
while(nde!=lca)
{
nde=anc[nde];
if(col[nde])
{
if(col[nde]==cor) return;
else printf(""),exit();
}
col[nde]=cor;
}
}
void Getans(int nde,int fth)
{
vint v1,v2;
dp[nde][(bool)col[nde]]=;
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=fth)
{
int g=goal[i]; Getans(g,nde);
int s=(dp[g][]+dp[g][])%mod;
v1.push_back(s),v2.push_back(s);
col[nde]?Mul(dp[nde][],s):Mul(dp[nde][],s);
}
if(!col[nde]&&v1.size())
{
int sz=v1.size(),pt=;
for(int i=;i<sz;i++) Mul(v1[i],v1[i-]);
for(int i=sz-;i>=;i--) Mul(v2[i],v2[i+]);
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=fth)
{
int pre=pt?v1[pt-]:,suf=(pt==sz-)?:v2[pt+];
int tmp=dp[goal[i]][];
Mul(tmp,pre),Mul(tmp,suf),Add(dp[nde][],tmp),pt++;
}
}
}
int main ()
{
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
{
scanf("%d",&col[i]);
if(col[i]) ve[col[i]].push_back(i);
}
for(int i=;i<n;i++)
scanf("%d%d",&t1,&t2),Link(t1,t2);
DFS(,,),Decompose(,);
for(int i=;i<=k;i++)
{
vint v=ve[i]; int lca=*v.begin();
if(v.size()>)
{
vit it=++v.begin();
while(it!=v.end())
lca=LCA(lca,*it++);
}
vit it=v.begin();
while(it!=v.end())
Climb(*it++,lca,i);
}
Getans(,);
// for(int i=1;i<=n;i++)
// printf("%d %d %d\n",mar[i],dp[i][0],dp[i][1]);
printf("%d",dp[][]);
return ;
}

解题:CF1118F2 Tree Cutting (Hard Version)的更多相关文章

  1. 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 ...

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

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

  3. 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 ...

  4. Tree Cutting (Hard Version) CodeForces - 1118F2 (树形DP,计数)

    大意:给定树, 每个点有颜色, 一个合法的边集要满足删除这些边后, 每个连通块内颜色仅有一种, 求所有合法边集的个数 $f[x][0/1]$表示子树$x$中是否还有与$x$连通的颜色 对于每种颜色已经 ...

  5. Codeforces 1118 F2. Tree Cutting (Hard Version) 优先队列+树形dp

    题目要求将树分为k个部分,并且每种颜色恰好在同一个部分内,问有多少种方案. 第一步显然我们需要知道哪些点一定是要在一个部分内的,也就是说要求每一个最小的将所有颜色i的点连通的子树. 这一步我们可以将所 ...

  6. CodeForces 1118F2. Tree Cutting (Hard Version)

    题目简述:给定$n \leq 3 \times 10^5$个节点的树,其中一部分节点被染色,一共有$k$种不同的颜色.求将树划分成 $k$ 个不相交的部分的方案数,使得每个部分中除了未染色的节点以外的 ...

  7. 【HDU 5909】 Tree Cutting (树形依赖型DP+点分治)

    Tree Cutting Problem Description Byteasar has a tree T with n vertices conveniently labeled with 1,2 ...

  8. BZOJ3391: [Usaco2004 Dec]Tree Cutting网络破坏

    3391: [Usaco2004 Dec]Tree Cutting网络破坏 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 47  Solved: 37[ ...

  9. BZOJ 3391: [Usaco2004 Dec]Tree Cutting网络破坏( dfs )

    因为是棵树 , 所以直接 dfs 就好了... ---------------------------------------------------------------------------- ...

随机推荐

  1. Python3入门(一)——概述与环境安装

    一.概述 1.python是什么 Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. Python 是一种解释型语言: 这意味着开发过程中没有了编译这个环节.类似于PHP和 ...

  2. Django Rest Framework源码剖析(一)-----认证

    一.简介 Django REST Framework(简称DRF),是一个用于构建Web API的强大且灵活的工具包. 先说说REST:REST是一种Web API设计标准,是目前比较成熟的一套互联网 ...

  3. 五、MYSQL的索引

    对于建立的索引(姓,名字,data) 5.1.索引对一下的查询类型有效 1.全值匹配:能查找姓+名为ALLEN.出生日期为1990-11-05的人: 2.最左前缀匹配:可以查找姓为ALLEN的人:即只 ...

  4. [CF986F]Oppa Funcan Style Remastered[exgcd+同余最短路]

    题意 给你 \(n\) 和 \(k\) ,问能否用 \(k\) 的所有 \(>1\) 的因子凑出 \(n\) .多组数据,但保证不同的 \(k\) 不超过 50 个. \(n\leq 10^{1 ...

  5. vue初学实践之路——vue简单日历组件(3)

    这一篇我们来实现管理员修改每一天剩余数量的功能. <div id="calendar"> <div id="left"> <spa ...

  6. DMS专线联通外网测试

    配置 CE Ping PE: “本地链接”-->属性-->"Internet 协议版本4(TCP/IPv4)",选择“使用下面的IP”,填写“172.16.10.21” ...

  7. Git的简单操作

    一.Git安装 windows下,可在在git官网下载(https://git-scm.com/downloads) 也有360提供的git(http://baoku.360.cn/soft/show ...

  8. UE4官方行为树快速入门文档解析和修改

    近学习了UE4官方文档的行为树快速入门指南,发现里面的部分逻辑稍稍有点混乱和重叠,于是加入了自己的想法,修改了部分行为树逻辑,优化了其AI寻路能力. 初始的基本操作和资源创建同官方文档一样:1个Fol ...

  9. PAT甲题题解-1068. Find More Coins (30)-dp,01背包

    一开始没多想,虽然注意到数据N<=10^4的范围,想PAT的应该不会超时吧,就理所当然地用dfs做了,结果最后一组真的超时了.剪枝啥的还是过不了,就意识到肯定不是用dfs做了.直到看到别人说用0 ...

  10. 读书笔记(chapter1-2)

    一.linux内核简介 1.1unix的历史 1.unix强大的根本原因:1.unix很简洁,仅仅提供几百个系统调用并且有一个非常明确的设计目的:2.在unix中,所有的东西都被当作文件对待:3.un ...