专栏文章

题解:CF979C Kuro and Walking Route

CF979C题解参与者 1已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mio3wu4n
此快照首次捕获于
2025/12/02 12:57
3 个月前
此快照最后确认于
2025/12/02 12:57
3 个月前
查看原文

题意

Kuro 想要在一棵树上选择两个不同的节点 uuvv 作为步行路线的起点和终点。但是,他避免选择那些路径上先经过节点 xx 再经过节点 yy(u,v)(u,v) 对。需要计算所有满足条件的 (u,v)(u, v) 对的数量。

分析

算法

图的遍历。

数据结构

数组,STL vector(邻接表存图)。

过程分析

观察到 1n3×1051\le n\le3\times10^5,考虑 O(n)O(n) 做法,即每个节点只遍历一次。
步骤:存图,DFS 两次计算 x,yx,y 节点的子树大小。

详细解法

  1. 输入 + 存图
CPP
cin >> n >> x >> y;
for (int i = 1; i < n; i++){
    int a, b;
    cin >> a >> b;
    g[a].push_back(b);
    g[b].push_back(a); //双向存图
}
  1. 我们知道这棵树共有 n×(n1)n\times(n-1)(u,v)(u,v) 对。且不难发现,若 uuxx 节点的子树,且 vvyy 节点的子树,那么 uuvv 的路径就一定不合规。我们可以以 yy 为根节点,遍历这棵树到达 xx 结束,则 nn 减去遍历过的节点数量,就是 xx 的子树大小。求 yy 用一样的思路。这样我们就可以得出,若 xx 的子树大小为 sxsxyysysy,不合规的点对数量为 sx×sysx\times sy,答案则为 n×(n1)sx×syn\times(n-1)-sx\times sy
CPP
shouldnot = y; //不能走到的节点
dfs(x, x); //从 x 开始遍历
int ans = n - sum; //记录子树大小
sum = 0;
shouldnot = x; //重置
dfs(y, y);
ans *= (n - sum);
cout << (n - 1) * n - ans;
  1. DFS 内部。
CPP
void dfs(int u, int f){ //当前节点和父节点
    if (u == shouldnot)
        return; //如果走到 shouldnot 节点,结束 DFS。
    sum++; //累加遍历过的数量
    for (int i : g[u]){ //遍历所有能到达的节点
        if (i != f) //防止走会父节点
            dfs(i, u); //更新 u,f
    }
}

总结

时间复杂度:O(n)O(n)
空间复杂度:O(n)O(n)
代码可通过:

评论

1 条评论,欢迎与作者交流。

正在加载评论...