考虑将每种颜色构成的极小连通块缩点,然后直接跑树形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. Python股票分析系列——系列介绍和获取股票数据.p1

    本系列转载自youtuber sentdex博主的教程视频内容 https://www.youtube.com/watch?v=19yyasfGLhk&index=4&list=PLQ ...

  2. eclipse 常用配置

    一.内置tomcat配置 解决eclipse 内置tomcat 与本地tomcat 端口冲突 传送门:http://www.cnblogs.com/tweet/p/7568979.html 二.字体设 ...

  3. MySQL 性能调优之SQL

    原文:http://bbs.landingbj.com/t-0-245451-1.html 对于SQL的优化,我们主要提供调整执行计划.优化SQL的方法有:缩短访问的路径.尽早过滤数据.尽可能减少排序 ...

  4. Angular 过滤器

    <!DOCTYPE html><html ng-app="myApp"><head lang="en"> <meta ...

  5. html 引入页面公共部分(header、footer)

    html引入页面的公共部分,比如导航栏啊,页头页脚之类的. 1.将需要引入的公共html部分转换为js文件,这里推荐一个转换工具地址 http://tool.chinaz.com/Tools/Html ...

  6. Python--文件、文件夹、压缩包、处理模块shutil

    高级的 文件.文件夹.压缩包 处理模块 shutil.copyfileobj(fsrc, fdst[, length])将文件内容拷贝到另一个文件中 1 import shutil 2 3 shuti ...

  7. hadoop的缺点

    Hadoop的限制 Hadoop只能执行批量处理,并且只以顺序方式访问数据.这意味着必须搜索整个数据集,即使是最简单的搜索工作.

  8. python之路--BOM和DOM

    一. 介绍 之前学的JS的一些简单的语法并没有和浏览器有任何的交互. 我们要想制作一些我们经常看到的网页的一些交互,我们需要继续学习BOM和DOM相关知识. JavaScript 分为 ECMAScr ...

  9. websocket协议握手详解

    最近使用tornado做长链接想着怎么着也要试试websocket协议吧.所以说干就干. 首先要知道websocket是基于http协议的,为什么这么说?因为从协议来说,websocket是借用了一部 ...

  10. WorldCount代码检查与优化——软件测试第三次作业

    合作者:201631062222,201631062232 代码地址:https://gitee.com/biubiubiuLYQ/ceshi_secend 本次作业链接地址:https://edu. ...