1 条题解

  • 0
    @ 2025-8-24 21:43:58

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar jiangchenyangsong
    你若决定灿烂,山无遮,海无拦。|| 4122

    搬运于2025-08-24 21:43:58,当前版本为作者最后更新于2022-10-23 14:27:26,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意

    一个树上每一个点都有一个组别,求相同组别的点对相差的最大距离。

    分析

    首先对于任意一个组别,深度最大的点一定在答案的点对里。

    证明

    假设答案的点对里没有深度最大的点,设深度最大的点为 xx,设点对中的点为 y,zy,z,假设 d[y]d[z]d[x]d[y]\leq d[z]\leq d[x] tty,zy,zlcalca

    1.若 z,yz,y 属于 tt 的不同子树,因为 d[y]d[x]d[y]\leq d[x]d[z]d[x]d[z]\leq d[x] ,若 xx 不在 tt 的子树内,那么,把 yy 换为 xx 会更优。若 xxtt 的子树内,如果 lca(x,z)=tlca(x,z)=t,显然可以将 yy 换成 xx。如果 lca(x,z)tlca(x,z)\ne t,那么很明显,将 zz 换成 xx 一定比点对 y,zy,z 的答案更优,或者点对 x,zx,z 比点对 x,yx,y 更优,显然不论哪种情况,xx 都在答案里。

    2.若 z,yz,y 属于 tt 的同一棵子树,即 y=ty=t,因为 d[y]d[x]d[y]\leq d[x]d[z]d[x]d[z]\leq d[x] ,若 xx 不在 yy 的子树内,那么把 yy 换成 xx 会更优,若在 yy 子树内,那么显然把 zz 换成 xx 更优。

    所以,对于不同组别,我们只需要求出深度最大的点即可,在 O(n)O(n) 枚举每一个点,与同组别深度最大的点求一遍 lcalca 更新答案。

    codecode

    #include<bits/stdc++.h>
    #define N 200005
    using namespace std;
    int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    queue<int> q;
    int n,k,root,tot,t;
    int a[N],p[N],d[N],f[N][25],maxd[N],ans[N],pos[N];
    int Head[N],to[N<<1],Next[N<<1];
    void add(int u,int v){to[++tot]=v,Next[tot]=Head[u],Head[u]=tot;}
    void bfs(int s){
    	q.push(s);d[s]=1,maxd[a[s]]=1;
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for(int i=Head[x];i;i=Next[i]){
    			int y=to[i];if(d[y]) continue;
    			d[y]=d[x]+1,f[y][0]=x;
    			if(maxd[a[y]]<d[y]) pos[a[y]]=y;
    			maxd[a[y]]=max(maxd[a[y]],d[y]);
    			for(int j=1;j<=t;j++) f[y][j]=f[f[y][j-1]][j-1];
    			q.push(y); 
    		}
    	}
    }
    int lca(int x,int y){
    	if(d[x]>d[y]) swap(x,y);
    	for(int j=t;j>=0;--j)
    		if(d[f[y][j]]>=d[x]) y=f[y][j];
    	if(x==y) return x;
    	for(int j=t;j>=0;--j)
    		if(f[y][j]!=f[x][j]) x=f[x][j],y=f[y][j];
    	return f[x][0];
    }
    int DIS(int x,int y){return d[x]+d[y]-2*d[lca(x,y)];}
    signed main(){
    	n=read(),k=read();
    	for(int i=1;i<=n;++i){
    		a[i]=read(),p[i]=read();
    		if(p[i]==0) root=i;
    		else add(i,p[i]),add(p[i],i);
    	}
    	t=log(n)/log(2)+1;
    	bfs(root);
    	for(int i=1;i<=n;++i) ans[a[i]]=max(ans[a[i]],DIS(pos[a[i]],i));
    	for(int i=1;i<=k;++i) printf("%d\n",ans[i]);
     	return 0;
    }
    
    • 1

    信息

    ID
    2036
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者