A 美丽的子树
A 美丽的子树
题目
【题目描述】
小 A 得到了一棵美丽的有根树。这棵树由 n 个节点以及 n - 1 条有向边构成,每条边都从父
亲节点指向儿子节点,保证除了根节点以外的每个节点都有一个唯一的父亲。树上的节点从1 到 n 标号。该树的一棵子树的定义为某个节点以及从该节点出发能够达到的所有节点的集合,显然这棵树共有 n 棵子树。小 A 认为一棵有根树是美丽的当且仅当这棵树内节点的标号
构成了一个连续的整数区间。现在小 A 想知道这棵树上共有多少棵美丽的子树。
【输入输出格式】
输入格式:
第一行有一个整数 n,表示树的节点数。
接下来 n–1 行,每行两个整数 u,v,表示存在一条从 u 到 v 的有向边。
输入保证该图是一棵有根树。
输出格式:
输出一个整数占一行,表示对应的答案。
【输入输出样例】
输入样例#1:
4
2 3
2 1
2 4
输出样例#1:
4
【数据范围】
\(n \leq 100000\)
测试数据(Google网盘)
思路
首先找到这个树的根节点,以根节点为起点dfs,维护每一个子树的大小(\(Size\)),最大节点值\(Max\),最小节点值\(Min\)。如果某个子树符合\(Max-Min+1=Size\),即为所求,答案+1 s
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int maxn=100000+5;
inline void read(int &mikoto) {
int misaka=0,flag=1;
char c=getchar();
while(c<'0' || c>'9') {
if(c=='-')
flag=-1;
c=getchar();
}
while(c>='0' && c<='9') {
misaka=misaka*10+(int)(c-'0');
c=getchar();
}
mikoto=misaka*flag;
}
int n,ans,Min[maxn],Max[maxn],size[maxn];
bool vis[maxn];
vector<int> tree[maxn];//动态数组模拟邻接表
inline void dfs(int rt) {
size[rt]=1;
Max[rt]=rt;
Min[rt]=rt;
int s=tree[rt].size();
for(int i=0; i<s; ++i) {
dfs(tree[rt][i]);
size[rt]+=size[tree[rt][i]];
Min[rt]=min(Min[rt],Min[tree[rt][i]]);
Max[rt]=max(Max[rt],Max[tree[rt][i]]);
}
Max[rt]=max(Max[rt],rt);
Min[rt]=min(Min[rt],rt);
if(Max[rt]-Min[rt]+1==size[rt]) {
ans++;
}
}
int main() {
ios::sync_with_stdio(false);
memset(Min,0x7f,sizeof(Min));
read(n);
for(int i=1; i<n; ++i) {
int u,v;
read(u);
read(v);
tree[u].push_back(v);
vis[v]=1;
}
int root;
for(int i=1; i<=n; ++i) {
if(!vis[i]) {
root=i;
break;
}
}
dfs(root);
cout<<ans;
return 0;
}