GMOJ 6807. 【2020.10.29提高组模拟】tree GMOJ 6807. 【2020.10.29提高组模拟】tree
题目描述
有一个 n 个节点的树,编号分别是 1 到 n,每个节点上有一个颜色,一共有 m 种颜色,保证每种颜色至少出现 1 次。
你需要选择一个点作为根,同时找一个树上节点的非空子集 T,满足每种颜色都至少在T 中出现一次,并且 T 中所有点的 LCA 的深度最大。定义你选的根深度为 1,儿子的深度是父亲深度+1。
题解
这道题考试时我只拿了75分,打的是线段树合并。
做法大致是一样的,枚举以哪个点作为(lca) ,然后分两种情况讨论:
- 点集T是当前点(x) 的子树,那么我们只需要找到(x) 上方离他最远的点就行了。
- 点集T是除(x) 外的子树,那么我们只需要找到(x) 下方离他最远的点就可以了。
现在的问题就只剩下如何判断(x) 的子树及外子树是否包含全部颜色就行了。
- 对于(x) 的子树,将同种颜色的点按(dfn) 序排序,然后将每个点到根的路径上标记加一,然后再减去相邻两个点的(lca) 到根的标记避免重复。可以用差分计算。
- 对于(x) 的子树外的点,可以找到同种颜色所有点的(lca) ,容易发现,从这个(lca) 到根上的路径上的所有点,他们的子树之外都是不包含所有点的。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000010
#define M 100010
#define K 20
using namespace std;
int n,m,col[N],tot,x,y,i,q[N],fa[N][K+1],dep[N],last[M],dfn[N],num,bz1[N],bz2[N],f[N],f1[N],g[N],clca[M],ans;
struct edge{
int to,next;
}e[N*2];
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
void insert(int x,int y){
tot++;
e[tot].to=y;
e[tot].next=q[x];
q[x]=tot;
}
void dfs_fa(int x,int father){
int i,y;
fa[x][0]=father;
dep[x]=dep[father]+1;
num++;
dfn[num]=x;
f[x]=1;
for (i=1;i<=K;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for (i=q[x];i;i=e[i].next){
y=e[i].to;
if (y!=father){
dfs_fa(y,x);
if (f[y]+1>f[x]) f1[x]=f[x],f[x]=f[y]+1;
else f1[x]=max(f1[x],f[y]+1);
}
}
}
void dfs_bz(int x,int father){
int i,y;
g[x]=g[father]+1;
if (f[x]+1==f[father]) g[x]=max(g[x],f1[father]+1);
else g[x]=max(g[x],f[father]+1);
for (i=q[x];i;i=e[i].next){
y=e[i].to;
if (y!=father){
dfs_bz(y,x);
bz1[x]+=bz1[y];
if (bz2[y]) bz2[x]=1;
}
}
}
int lca(int x,int y){
int i;
if (dep[x]<dep[y]) swap(x,y);
for (i=K;i>=0;i--)
if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if (x==y) return x;
for (i=K;i>=0;i--)
if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n=read();m=read();
for (i=1;i<=n;i++) col[i]=read();
for (i=1;i<n;i++){
x=read();y=read();
insert(x,y);
insert(y,x);
}
dfs_fa(1,0);
for (i=1;i<=n;i++){
bz1[dfn[i]]++;
if (last[col[dfn[i]]])
bz1[lca(last[col[dfn[i]]],dfn[i])]--;
if (!clca[col[dfn[i]]]) clca[col[dfn[i]]]=dfn[i];
else clca[col[dfn[i]]]=lca(dfn[i],clca[col[dfn[i]]]);
last[col[dfn[i]]]=dfn[i];
}
for (i=1;i<=m;i++)
bz2[clca[i]]=1;
dfs_bz(1,0);
for (i=1;i<=n;i++){
if (bz1[i]==m) ans=max(ans,g[i]);
if (!bz2[i]) ans=max(ans,f[i]+1);
}
printf("%d
",ans);
return 0;
}