Codeforces Round #540 Div. 3 F2
考虑将每种颜色构成的极小连通块缩点,然后直接跑树形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的更多相关文章
- Codeforces Round #540 (Div. 3) 部分题解
Codeforces Round #540 (Div. 3) 题目链接:https://codeforces.com/contest/1118 题目太多啦,解释题意都花很多时间...还有事情要做,就选 ...
- 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> ...
- Codeforces Round #540 (Div. 3)--1118C - Palindromic Matrix
https://codeforces.com/contest/1118/problem/C 在查找元素的时候,必须按4,2,1的顺序进行.因为,如果先找1,可能就把原来的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 ...
- Codeforces Round #540 (Div. 3)--1118D2 - Coffee and Coursework (Hard Version)
https://codeforces.com/contest/1118/problem/D2 和easy version的主要区别是,数据增加了. easy version采用的是线性查找,效率低 在 ...
- Codeforces Round #540 (Div. 3)--1118D1 - Coffee and Coursework (Easy version)
https://codeforces.com/contest/1118/problem/D1 能做完的天数最大不超过n,因为假如每天一杯咖啡,每杯咖啡容量大于1 首先对容量进行从大到小的排序, sor ...
- Codeforces Round #540 (Div. 3)题解
题目链接: https://codeforces.com/contest/1118 A题: 题意: q次查询,给你一个n,要你用1和2来凑出n,1的花费为a,2的花费为b,求花费的最小值. 思路: 我 ...
- 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 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 ...
随机推荐
- Tomcat完美配置多个HOST主机,域名,SSL
这里是Tomcat9版本,其它版本基本一致! 1.配置多个主机域名 1.打开conf文件夹下的server.xml 复制官方提供的HOST配置,修改为你的域名,appBase路径(相对路径) 2.新建 ...
- 深入浅出Tomcat系列
原本打算一篇文章就发了的,无奈文章太长,阅读压力较大.为了让阅读体验更好一些,还是分多篇吧,大概6篇. 下面是这个主题的目录: 深入浅出Tomcat/1- 来历和配置文件 深入浅出Tomcat/2 - ...
- 面试 6:拓展性更好的代码,更容易拿到 Offer
今天给大家带来的是 <剑指 Offer>习题:调整数组顺序使奇数位于偶数前面,纯 Java 实现希望大家多加思考. 面试题:输入一个整型数组,实现一个函数来调整该数组中的数字的顺序,使 ...
- Wechart 饼图
预览 Preview | Usage Source | Pie Source | Tutorial Wechart by Cax Cax 众所周知 Cax 既能开发游戏.又能开发图表.本文将从饼图开始 ...
- 9宫拼图小游戏(WPF MVVM实现)
昨天逛论坛,看到一个哥们用WPF做了一个9宫的拼图游戏,发现初学WPF的人都很容易犯一个错误(我也犯过):把WPF当WINFORM用!所以想写一个比较符合WPF风格的版本,于是就抽工作的空余时间做了一 ...
- 通用权限管理系统多语言开发标准接口 - java,php 调用标准接口程序参考
1:公司里有多个业务系统,需要进行统一重构,有PHP的.有Java的.有.NET的,甚至还有 Delphi 的. 2:公司里有多个数据库系统,有mysql的.有sqlserver的.还有oracel的 ...
- PyCharm Debug 调试
断点(breakpoint),表示标记一行的位置,当程序运行到该行代码的时候,会将程序暂时暂停,以便对该行代码进行分析. 编辑python脚本,debug.py def hello(): return ...
- Dubbo负载均衡与集群容错机制
1 Dubbo简介 Dubbo是一款高性能.轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现. 作为一个轻量级RPC框架,D ...
- 自己实现数据结构系列四---Queue
一.代码部分 1.定义接口: public interface Queue<E> { void enqueue(E e); E dequeue(); E getFront(); int g ...
- mysql 无法退出sql命令行编辑
mysql 无法退出sql命令行编辑 | ANBOBhttp://www.anbob.com/archives/579.html mysql 无法退出sql命令行编辑 - 码农甲乙丙 - CSDN博客 ...