【记忆化搜索】珂朵莉的值域连续段 牛客练习赛9B

链接:https://www.nowcoder.com/acm/contest/40/B
来源:牛客网

题目描述

珂朵莉给你一个有根树,求有多少个子树满足其内部节点编号在值域上连续

一些数在值域上连续的意思即其在值域上构成一个连续的区间

输入描述:

第一行有一个整数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


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

const int mn = 100010;

int n;
queue<int>q[mn];
int mp[mn][3];  //0 区间最小值 1 区间最大值 2 节点数
bool vis[mn];

void dfs(int s)
{
	int m=s,M=s,k=1;
	while(!q[s].empty())
	{
		int t = q[s].front();
		q[s].pop();

		dfs(t);
		//以t为根节点

		m=min(m,mp[t][0]); //当前最小值+=子树节点数
		M=max(M,mp[t][1]); //当前最大值+=子树节点数
		k+=mp[t][2];  //当前节点数+=子树节点数
	}
	mp[s][0]=m;
	mp[s][1]=M;
	mp[s][2]=k;
}

int main()
{
	scanf("%d",&n);

	for(int i=1;i<=n;i++)
	{
		mp[i][0]=1e9;
		mp[i][1]=-1;
	}

	for(int i=1;i<n;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		q[a].push(b);
		vis[b]=1;
	}

	for(int i=1;i<=n;i++)
		if(!vis[i])
		dfs(i);  //根节点

	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(mp[i][2]==mp[i][1]-mp[i][0]+1)
			ans++;
	}
	printf("%d\n",ans);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/ummmmm/article/details/80334618