tREe 题解

tREe 题解

曾用于校内训练:YAOI Round #26 (Div.1+Div.2) F. 猴皮面包树

U248852 tREe - 洛谷

简要题意

给定一棵树的根结点和有连边的点的编号(但不知道哪个点是父结点,也就是说输入的 u,v 可能是 u 为 v 的父结点,也可能相反)。询问一些点的父结点编号、深度、距离它最远的结点编号、子树大小。

分析

由于已知树的根结点,我们可以从根结点出发向下进行一次深搜,便可处理出每个点的父结点、深度和子树大小了。这是简单的。

求距离最远的结点编号,一个容易想到的方法是从这个点出发进行深搜,但这种做法是低效的。这时我们需要用到一个重要性质:在树上从任意结点开始进行一次 dfs,到达的距离其最远的结点必为直径的一端。

因此我们在 dfs 中求出树的直径的两端,再预处理出这两个端点到树上每一点的距离(一共是三次深搜,第一次处理基本信息和直径一端,第二次求到直径一端的距离和直径的另一端,第三次求距离)。查询时候只需要把两个距离比较取最大就可以了。

此外需要注意一个细节:在处理两个距离时要 dis[0]=-1,因为一个结点到自己的距离为 0,但深搜起始点的距离会被赋值为 dis[0]+1

代码

#include<bits/stdc++.h>
using namespace std;

int read(){
    int w=0,ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')w=w*10+ch-48,ch=getchar();
    return w; 
}

#define MAXN 1000003
int n,r,q;
int fa[MAXN],dep[MAXN],siz[MAXN];
int p1,p2,dis1[MAXN],dis2[MAXN];

struct edge{
    int v,nxt;
}e[MAXN<<1];
int head[MAXN],ecnt;
void build(int u,int v){
    e[++ecnt].v=v;
    e[ecnt].nxt=head[u],head[u]=ecnt;
}

void dfs1(int u,int fath){
    fa[u]=fath,dep[u]=dep[fath]+1,siz[u]=1;// 维护三个数据
    if(dep[u]>dep[p1])p1=u;// 求出直径一端
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==fath)continue;
        dfs1(v,u);
        siz[u]+=siz[v];// 求子树大小
    }
}

void dfs2(int u,int fath){
    dis1[u]=dis1[fath]+1;// 求第一个距离
    if(dis1[u]>dis1[p2])p2=u;// 求出直径另一端
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==fath)continue;
        dfs2(v,u);
    }
}

void dfs3(int u,int fath){
    dis2[u]=dis2[fath]+1;// 求第二个距离
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==fath)continue;
        dfs3(v,u);
    }
}

int main(){
    n=read(),r=read(),q=read();
    for(int i=1;i<n;i++){
        int u=read(),v=read();
        build(u,v),build(v,u);
    }
    dis1[0]=dis2[0]=-1;// 细节
    dfs1(r,0),dfs2(p1,0),dfs3(p2,0);
    while(q--){
        int op=read(),x=read();
        if(op==1)printf("%d\n",fa[x]);
        else if(op==2)printf("%d\n",dep[x]);
        else if(op==3)printf("%d\n",max(dis1[x],dis2[x]));
        else printf("%d\n",siz[x]);
    }
    return 0;
}
posted @ 2022-11-23 18:51  ofbwyx  阅读(35)  评论(0)    收藏  举报