考虑将每种颜色构成的极小连通块缩点,然后直接跑树形dp即可,即f[i][0/1]表示子树内是否有颜色向上延伸时删边的方案数。dp时需要去除某点的贡献,最好用前后缀积的做法而不是求逆。

  至于如何缩点,假装要给每种颜色建虚树,按dfs序排一下序找到所有虚树上的边,标记所有虚树上的点(包括不在虚树中但在虚树上两点的路径中)即可。然后重建树。注意标记过程中判一下无解。

  (这个div3F代码长度怎么跟我div1F差不多了啊?

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define P 998244353
#define N 300010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,a[N],p[N<<1],dfn[N],fa[N][20],deep[N],f[N<<1],F[N<<1][2],pre[N<<1],suf[N<<1],t,T,cnt,stk[N],top;
vector<int> pos[N];
struct data{int to,nxt;
}edge[N<<1],tree[N<<2];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void new_addedge(int x,int y){T++;tree[T].to=y,tree[T].nxt=p[x],p[x]=T;}
void dfs(int k)
{
dfn[k]=++cnt;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=fa[k][0])
{
fa[edge[i].to][0]=k;
deep[edge[i].to]=deep[k]+1;
dfs(edge[i].to);
}
}
bool cmp(const int&a,const int&b)
{
return dfn[a]<dfn[b];
}
int lca(int x,int y)
{
if (deep[x]<deep[y]) swap(x,y);
for (int j=19;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];
if (x==y) return x;
for (int j=19;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
bool paint(int x,int y,int color)
{
while (x!=y)
{
if (f[x]>n&&f[x]!=color) return 1;
f[x]=color;x=fa[x][0];
}
return 0;
}
void dp(int k,int from)
{
for (int i=p[k];i;i=tree[i].nxt)
if (tree[i].to!=from) dp(tree[i].to,k);
if (k>n)
{
F[k][0]=0;F[k][1]=1;
for (int i=p[k];i;i=tree[i].nxt)
if (tree[i].to!=from) F[k][1]=1ll*F[k][1]*(F[tree[i].to][0]+F[tree[i].to][1])%P;
}
else
{
F[k][0]=1;int cnt=0;
for (int i=p[k];i;i=tree[i].nxt)
if (tree[i].to!=from)
{
F[k][0]=1ll*F[k][0]*(F[tree[i].to][0]+F[tree[i].to][1])%P;
pre[++cnt]=F[tree[i].to][0]+F[tree[i].to][1];
}
for (int i=1;i<=cnt;i++) suf[i]=pre[i];
pre[0]=1;for (int i=1;i<=cnt;i++) pre[i]=1ll*pre[i-1]*pre[i]%P;
suf[cnt+1]=1;for (int i=cnt;i>=1;i--) suf[i]=1ll*suf[i]*suf[i+1]%P;
int t=0;
for (int i=p[k];i;i=tree[i].nxt)
if (tree[i].to!=from)
{
t++;
F[k][1]=(F[k][1]+1ll*pre[t-1]*suf[t+1]%P*F[tree[i].to][1])%P;
}
}
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("f.in","r",stdin);
freopen("f.out","w",stdout);
#endif
n=read(),m=read();
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<n;i++)
{
int x=read(),y=read();
addedge(x,y),addedge(y,x);
}
fa[1][0]=1;dfs(1);
for (int j=1;j<20;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for (int i=1;i<=n;i++)
if (a[i]) f[i]=n+a[i],pos[a[i]].push_back(i);else f[i]=i;
for (int i=1;i<=m;i++)
if (pos[i].size()>1)
{
sort(pos[i].begin(),pos[i].end(),cmp);
int root=(*pos[i].begin());
for (int j=0;j<pos[i].size()-1;j++)
if (deep[lca(pos[i][j],pos[i][j+1])]<deep[root]) root=lca(pos[i][j],pos[i][j+1]);
if (f[root]>n&&f[root]!=n+i) {cout<<0;return 0;}
top=0;stk[++top]=root;f[root]=n+i;
for (int j=((*pos[i].begin())==root);j<pos[i].size();j++)
{
int l=lca(stk[top],pos[i][j]);
if (l!=stk[top])
{
while (top>1&&deep[l]<=deep[stk[top-1]])
{
if (paint(stk[top],stk[top-1],n+i)) {cout<<0;return 0;}
top--;
}
if (paint(stk[top],l,n+i)) {cout<<0;return 0;}
stk[top]=l;
}
stk[++top]=pos[i][j];
}
while (top>1)
{
if (paint(stk[top],stk[top-1],n+i)) {cout<<0;return 0;}
top--;
}
}
//for (int i=1;i<=n;i++) cout<<f[i]<<' ';cout<<endl;
memset(p,0,sizeof(p));
for (int i=1;i<=t;i+=2)
if (f[edge[i].to]!=f[edge[i+1].to])
new_addedge(f[edge[i].to],f[edge[i+1].to]),
new_addedge(f[edge[i+1].to],f[edge[i].to]);
dp(n+1,n+1);
cout<<F[n+1][1];
return 0;
//NOTICE LONG LONG!!!!!
}

  

Codeforces Round #540 Div. 3 F2的更多相关文章

  1. Codeforces Round #540 (Div. 3) 部分题解

    Codeforces Round #540 (Div. 3) 题目链接:https://codeforces.com/contest/1118 题目太多啦,解释题意都花很多时间...还有事情要做,就选 ...

  2. Codeforces Round #540 (Div. 3) A,B,C,D2,E,F1

    A. Water Buying 链接:http://codeforces.com/contest/1118/problem/A 实现代码: #include<bits/stdc++.h> ...

  3. Codeforces Round #540 (Div. 3)--1118C - Palindromic Matrix

    https://codeforces.com/contest/1118/problem/C 在查找元素的时候,必须按4,2,1的顺序进行.因为,如果先找1,可能就把原来的4拆散了,然后再找4,就找不到 ...

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

  5. Codeforces Round #540 (Div. 3)--1118D2 - Coffee and Coursework (Hard Version)

    https://codeforces.com/contest/1118/problem/D2 和easy version的主要区别是,数据增加了. easy version采用的是线性查找,效率低 在 ...

  6. Codeforces Round #540 (Div. 3)--1118D1 - Coffee and Coursework (Easy version)

    https://codeforces.com/contest/1118/problem/D1 能做完的天数最大不超过n,因为假如每天一杯咖啡,每杯咖啡容量大于1 首先对容量进行从大到小的排序, sor ...

  7. Codeforces Round #540 (Div. 3)题解

    题目链接: https://codeforces.com/contest/1118 A题: 题意: q次查询,给你一个n,要你用1和2来凑出n,1的花费为a,2的花费为b,求花费的最小值. 思路: 我 ...

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

  9. Codeforces Round #540 (Div. 3) D1. Coffee and Coursework (Easy version) 【贪心】

    任意门:http://codeforces.com/contest/1118/problem/D1 D1. Coffee and Coursework (Easy version) time limi ...

随机推荐

  1. 海纳百川而来的一篇相当全面的Java NIO教程

    目录 零.NIO包 一.Java NIO Channel通道 Channel的实现(Channel Implementations) Channel的基础示例(Basic Channel Exampl ...

  2. ML.NET 示例:推荐之One Class 矩阵分解

    写在前面 准备近期将微软的machinelearning-samples翻译成中文,水平有限,如有错漏,请大家多多指正. 如果有朋友对此感兴趣,可以加入我:https://github.com/fei ...

  3. Linux 命令(二)

    man help:线上查询及帮助命令 命令  --help:简单帮助 help  cd:查看一些Linux命令行的一些内置命令 文件和目操作命令(19个) ls  cd  cp  find  mkdi ...

  4. sql存储过程中使用 output、nvarchar(max)

    1.sql存储过程中使用 output CREATE PROCEDURE [dbo].[P_Max] @a int, -- 输入 @b int, -- 输入 @Returnc int output - ...

  5. 软件工程练习:模块化,单元测试,回归测试,TDD

    这是<构建之法>实战教学的一部分.适合作为同学们的第二个程序作业. 第一个程序作业: 请看 “概论” 一章的练习,或者老师的题目,例如这个. 作业要求: 软件工程的作业越来越有意思了, 我 ...

  6. Tea Party CodeForces - 808C (构造+贪心)

    Polycarp invited all his friends to the tea party to celebrate the holiday. He has ncups, one for ea ...

  7. 一个6亿的表a,一个3亿的表b,通过外间tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录

    1.如果A表TID是自增长,并且是连续的,B表的ID为索引 select * from a,b where a.tid = b.id and a.tid>500000 limit 200; 2. ...

  8. 使用Vue自己做一个简单的MarkDown在线编辑器

    1.首先要下载mark组件. npm install marked --save 2.在Vcontent.vue中简单写一些样式. <template> <div class=&qu ...

  9. 集大软件工程15级结对编程week1

    集大软件工程15级结对编程week1 0. 团队成员 姓名 学号 博客园首页 码云主页 孙志威 20152112307 Agt Eurekaaa 孙慧君 201521123098 野原泽君 野原泽君 ...

  10. semantic-ui 图片

    1.基础样式 方式一:因为图片是使用img标签,所以直接将class加载img标签中即可.不过要注意的是,class中要指定是ui image. 方式二:使用一个span或者div将img标签包裹,然 ...