当思路是枚举+判断时,要尝试去推答案具有的性质,以优化算法。
一个政党中距离最大的那个点对中,一定有一个点是该政党中深度最大的。
预处理每个政党深度最大的节点,之后枚举另一个点。
// q.c
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int M=200000+10;
/****************************************************************************/
struct Edge {
int u,v,nex; Edge() {}
Edge(int a,int b,int c):u(a),v(b),nex(c) {}
}ed[M<<1];
int head[M],cnt;
void add_edge(int a,int b) {
ed[cnt]=Edge(a,b,head[a]); head[a]=cnt++;
ed[cnt]=Edge(b,a,head[b]); head[b]=cnt++;
}
/****************************************************************************/
int f[M],dep[M],size[M],son[M];
void dfs1(int u,int fa,int d) {
f[u]=fa; dep[u]=d; size[u]=1;
int i; Edge e;
for(i=head[u];~i;i=ed[i].nex) {
e=ed[i];
if(!f[e.v]) {
dfs1(e.v,u,d+1); size[u]+=size[e.v];
if(size[e.v]>size[son[u]]||!son[u]) son[u]=e.v;
}
}
}
int top[M];
void dfs2(int u,int TP) {
top[u]=TP; if(!son[u]) return ;
dfs2(son[u],TP);
int i; Edge e;
for(i=head[u];~i;i=ed[i].nex) {
e=ed[i];
if(e.v!=f[u]&&e.v!=son[u]) dfs2(e.v,e.v);
}
}
/****************************************************************************/
int lca(int a,int b) {
while(top[a]!=top[b]) {
if(dep[top[a]]<dep[top[b]]) swap(a,b);
a=f[top[a]];
}
return dep[a]<dep[b]?a:b;
}
/****************************************************************************/
int deep[M],nd[M],ans[M],party[M];
int main() {
freopen("cowpol.in","r",stdin);
freopen("cowpol.out","w",stdout);
memset(head,-1,sizeof(head));
memset(deep,-1,sizeof(deep));
int n,k,b,rt;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
scanf("%d%d",&party[i],&b);
if(!b) { rt=i; continue; }
add_edge(i,b);
}
dfs1(rt,-1,0); dfs2(rt,rt);
for(int i=1;i<=n;i++) {
if(dep[i]>deep[party[i]]) {
deep[party[i]]=dep[i];
nd[party[i]]=i;
}
}
for(int i=1;i<=n;i++) {
b=lca(i,nd[party[i]]);
ans[party[i]]=max(ans[party[i]],dep[i]+deep[party[i]]-(dep[b]<<1));
}
for(int i=1;i<=k;i++) {
printf("%d\n",ans[i]);
}
return 0;
}