解题:CF1118F2 Tree Cutting (Hard Version)
好题不问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)的更多相关文章
- 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 ...
- Codeforces 1118F1 Tree Cutting (Easy Version) (简单树形DP)
<题目链接> 题目大意: 给定一棵树,树上的点有0,1,2三中情况,0代表该点无色.现在需要你将这棵树割掉一些边,使得割掉每条边分割成的两部分均最多只含有一种颜色的点,即分割后的两部分不能 ...
- 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 ...
- Tree Cutting (Hard Version) CodeForces - 1118F2 (树形DP,计数)
大意:给定树, 每个点有颜色, 一个合法的边集要满足删除这些边后, 每个连通块内颜色仅有一种, 求所有合法边集的个数 $f[x][0/1]$表示子树$x$中是否还有与$x$连通的颜色 对于每种颜色已经 ...
- Codeforces 1118 F2. Tree Cutting (Hard Version) 优先队列+树形dp
题目要求将树分为k个部分,并且每种颜色恰好在同一个部分内,问有多少种方案. 第一步显然我们需要知道哪些点一定是要在一个部分内的,也就是说要求每一个最小的将所有颜色i的点连通的子树. 这一步我们可以将所 ...
- CodeForces 1118F2. Tree Cutting (Hard Version)
题目简述:给定$n \leq 3 \times 10^5$个节点的树,其中一部分节点被染色,一共有$k$种不同的颜色.求将树划分成 $k$ 个不相交的部分的方案数,使得每个部分中除了未染色的节点以外的 ...
- 【HDU 5909】 Tree Cutting (树形依赖型DP+点分治)
Tree Cutting Problem Description Byteasar has a tree T with n vertices conveniently labeled with 1,2 ...
- BZOJ3391: [Usaco2004 Dec]Tree Cutting网络破坏
3391: [Usaco2004 Dec]Tree Cutting网络破坏 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 47 Solved: 37[ ...
- BZOJ 3391: [Usaco2004 Dec]Tree Cutting网络破坏( dfs )
因为是棵树 , 所以直接 dfs 就好了... ---------------------------------------------------------------------------- ...
随机推荐
- Android Notification的使用 - z
http://blog.csdn.net/new_one_object/article/details/55511253 另,博主其它文章也很好
- 20155328 《网络攻防》 实验一:PC平台逆向破解(5)M
20155328 <网络攻防> 实验一:PC平台逆向破解(5)M 实践目标 实践对象:linux可执行文件pwn1. 正常执行时,main调用foo函数,foo函数会简单回显任何用户输入的 ...
- 20155330 《网络攻防》Exp1 PC平台逆向破解(5)M
20155330 <网络攻防>Exp1 PC平台逆向破解(5)M 实践目标 运行pwn1可执行文件中的getshell函数,学习如何注入运行任何Shellcode 本次实践的对象是一个名为 ...
- [JOI2017春季合宿]Port Facility[set、二分图]
题意 你有两个栈,有 \(n\) 个货物,每个货物有一个进栈时间和出栈时间(所有时间的并集是1~2n),问有多少种不同的入栈方案. \(n\le 10^6\) 分析 把每个货物的存在看成区间,相交的区 ...
- 后端自动构建前端css和js
引子: 别的复杂前端开发技术不会,用得多的还是手写代码,手动处理. 3年前手写合并压缩js和css文件的asp脚本代码目前还能正常运行,也就没有多大使用别的技术的动力. 直到近期被一个问题纠结着,今天 ...
- Android——界面特效 相关知识总结贴
帮助android UI实现动画特效 http://www.apkbus.com/android-79595-1-1.html 帮助android应用程序实现动画特效 http://www.apkbu ...
- php faker 库填充数据
Generating Fake Data in PHP with Faker 时间 2016-01-28 07:13:00 Wern Ancheta 原文 http://wern-ancheta.c ...
- Boyer and Moore Fast majority vote algorithm(快速选举算法)
问题来来自于leetcode上的一道题目,https://leetcode.com/problems/majority-element/,大意是是找出一个数组中,出现次数超过一个半的数字,要求是O(n ...
- docker-compose编排
创建并启动容器 docker-compose up -d 备注: -d 后台启动并运行容器 前提是你在执行该命令的时候已经编写好了docker-compose.yml文件,在这个文件的当前目录执行上述 ...
- Jenkins 构建运行java程序
我们将在Jenkins建立执行一个简单的 HelloWorld 应用程序,构建和运行Java程序.打开网址:http://localhost:8080/jenkins 第1步- 转到Jenkins 仪 ...