洛谷 P11962:[GESP202503 六级] 树上漫步 ← dfs + 链式前向星

【题目来源】
https://www.luogu.com.cn/problem/P11962

【题目描述】
小 A 有一棵 n 个结点的树,这些
结点依次以 1,2,⋯,n 标号
小 A 想在这棵树上漫步。具体来说,小 A 会从树上的某个结点出发,每⼀步可以移动到与当前结点相邻的结点,并且小 A 只会在
偶数步(可以是零步)后结束漫步。
现在小 A 想知道,对于树上的每个结点,从这个结点出发开始漫步,经过偶数步能结束漫步的结点有多少个(可以经过重复的节点)。

【输入格式】
第一行,一个正整数 n。
接下来 n-1 行,每行两个整数 ui,vi,表示树上有一条连接结点 ui 和结点 vi 的边。

【输出格式】
一行,n 个整数。第 i 个整数表示从结点 i 出发开始漫步,能结束漫步的结点数量。

【输入样例 1】
3
1 3
2 3

【输出样例 1】
2 2 1

【输入样例 2】
4
1 3
3 2
4 3

【输出样例 2】
3 3 1 3

【数据范围】
对于 40% 的测试点,保证 1≤n≤
10^3
对于所有测试点,保证 1≤n≤
2×10^5

【算法分析】
● 以任意点为树根做一次 dfs,求出每个点的深度。深度为偶数的点可以通过偶数步到达深度为偶数的任意点,深度为奇数的点可以通过偶数步到达深度为奇数的任意点。
● 核心代码逻辑解析

for(int i=1; i<=n; i++) {
    if(st[i]) cout<

● 链式前向星:https://blog.csdn.net/hnjzsyjyj/article/details/139369904
e[idx]:存储序号为 idx 的边的终点值
ne[idx]:存储序号为 idx 的边指向的边的序号(模拟链表指针)‌
h[a]:存储头结点 a 指向的边的序号
val[idx]:存储序号为 idx 的边的权值(可选)

【算法代码】

#include 
using namespace std;

const int N=2e5+5;
bool st[N];
int e[N<<1],ne[N<<1],h[N],idx;
int n,cnt;

void add(int a,int b) {
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int u,int step) {
    if(st[u]) return;
    if(step%2 == 0) {
        st[u]=1;
        cnt++;
    }

    for(int i=h[u]; i!=-1; i=ne[i]) {
        int j=e[i];
        dfs(j,step+1);
    }
}

int main() {
    cin>>n;
    memset(h,-1,sizeof h);

    for(int i=1; i>a>>b;
        add(a,b), add(b,a);
    }

    dfs(1,0);

    for(int i=1; i<=n; i++) {
        if(st[i]) cout<



【参考文献】
https://blog.csdn.net/guolianggsta/article/details/146534885
https://blog.csdn.net/hnjzsyjyj/article/details/139369904
https://www.luogu.com.cn/problem/solution/P11962



 

你可能感兴趣的:(信息学竞赛,#,树与二叉树,#,搜索算法,dfs,链式前向星)