任意根求答案:换根dp(其实换根只在预处理有用。。。)
考虑如何打暴力。
如果有一个节点,他的子树(包含它)中有 \(m\) 中颜色,那么它就可以是候选答案,于是考虑如何求出所有这样的子树。
然后有个小技巧:对于这种子树上统计的问题,可以考虑 dfs 序,因为一颗子树的 dfs 序是连续的。
然后这里可以双指针进行操作,然后每次贪心地找最小的一段,再判断是否为子树(若不是则一定可以不为答案,\(l\) 在之前 (\(l,r\) 的 LCA)时就已考虑)。
考虑每个丶i,则 \(T\) 可分类为在 i 的子树上的和不在的。在的可以按上述方法求,即为符合条件的 i 向上的最大值。
然后我们可以预处理出每个丶向上和向下的最长连,然后考虑 \(T\) 不在的情况。
首先 i 的子树的 dfs 序是连续的,而实际上 dfs 序可以构成一个环,因此不在子树点上的 dfs 序也是连续的,于是我们可以断环成链,然后处理,注释中有解释。
主要启发:1.不定根-换根 dp,还可以枚举无根树的所有子树,用定根+枚举子树与补树的方法来遍历原树的所有子树
2.处理子树上的问题-dfs 序,要处理补树可以考虑环形的 dfs 序
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
const int M=1e5+7;
template <class I>
inline void read(I &x){
int f=1;
char c;
for(c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+(c&15),c=getchar());
x*=f;
}
int tot=1,head[N],ver[2*N],nxt[2*N],a[N],f[N],g[N],f2[N],T,rnk[2*N],ans,sz[N],n,m,c[N];
inline void add(int x,int y){
ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
}
void dfs(int x,int fa){
rnk[++T]=x;
sz[x]=1;
f[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa) continue;
dfs(y,x);
sz[x]+=sz[y];
if(f[y]+1>f[x])
f2[x]=f[x],f[x]=f[y]+1;
else if(f[y]+1>f2[x])
f2[x]=f[y]+1;
}
}
void dfs2(int x,int fa){
g[x]=g[fa]+1;
if(f[x]+1<f[fa]) g[x]=max(g[x],f[fa]+1);
else g[x]=max(g[x],f2[fa]+1);
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa) continue;
dfs2(y,x);
}
}
inline void calc1(){
int l,r,cnt=0;
l=r=n;
while(l>=1){//注意 l 实际上是枚举的 i,然后用贪心的思想判断子树是否合法,若固定 r 则求出来的东西没任何意义
if(!c[a[rnk[l]]]++) ++cnt;
while(cnt==m&&c[a[rnk[r]]]>1) --c[a[rnk[r--]]];
if(cnt==m&&r<l+sz[rnk[l]])
ans=max(ans,g[rnk[l]]-1);
--l;
}
}
inline void calc2(){
int l,r,cnt=0;
l=r=1;
while(r<=2*n){//这里 r 实际上并不是枚举的 i,因为我们把 r 的颜色统计进去了,所以 r 实际上是 i-1
if(!c[a[rnk[r]]]++) ++cnt;
while(cnt==m&&c[a[rnk[l]]]>1) --c[a[rnk[l++]]];
if(cnt==m&&r>n&&l>=r-n+1+sz[rnk[r+1]])//r>n 显然要满足,然后结合上述意义可知 l 一定不在 r+1 的子树中
ans=max(ans,f[rnk[r+1]]);
++r;
}
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;i++)
read(a[i]);
for(int i=1;i<n;i++){
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
g[0]=-1;
dfs(1,0);
dfs2(1,0);
for(int i=1;i<=n;i++)
rnk[i+n]=rnk[i];
calc1();
memset(c,0,sizeof(c));
calc2();
printf("%d\n",ans+1);
return 0;
}