题目链接:https://www.nowcoder.com/acm/contest/40/B
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
珂朵莉给你一个有根树,求有多少个子树满足其内部节点编号在值域上连续
一些数在值域上连续的意思即其在值域上构成一个连续的区间
输入描述:
第一行有一个整数n,表示树的节点数。 接下来n–1行,每行两个整数x,y,表示存在一条从x到y的有向边。 输入保证是一棵有根树。
输出描述:
输出一个数表示答案
示例1
输入
5 2 3 2 1 2 4 4 5
输出
5
说明
节点1子树中编号为1,值域连续 节点3子树中编号为3,值域连续 节点5子树中编号为5,值域连续 节点4子树中编号为4,5,值域连续 节点2子树中编号为1,2,3,4,5,值域连续
备注:
对于100%的数据,有n <=100000
解析:昨天晚上有思路,但是不会实现,今天上午看别人代码给A了,就是每次记录子树中包含元素的个数,以及最大和最小的值,如果该子树所有值是连续的,那么它的元素个数必然等于它所包含值的最大值减去最小值再加1。 即:个数 = mx - mi + 1
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100006;
vector<int> mp[maxn];
int f[maxn], dp[maxn], mi[maxn], mx[maxn];
void dfs(int x)
{
dp[x] = 1;
mi[x] = mx[x] = x;
for(auto v : mp[x])
{
dfs(v);
dp[x] += dp[v];
mx[x] = max(mx[x], mx[v]);
mi[x] = min(mi[x], mi[v]);
}
}
int main()
{
int n;
scanf("%d", &n);
int u, v;
int s = 1;
for(int i = 1; i < n; i++)
{
scanf("%d%d", &u, &v);
mp[u].push_back(v);
f[v]++;
}
for(int i = 1; i <= n; i++) if(!f[i]) s = i;
dfs(s);
int ans = 0;
for(int i = 1; i <= n; i++) ans += (dp[i] == mx[i] - mi[i] + 1);
printf("%d\n", ans);
return 0;
}