Codeforces Round #787 D. Vertical Paths

[Codeforces Round #787]

D. Vertical Paths

You are given a rooted tree consisting of n vertices. Vertices are numbered from 11 to n. Any vertex can be the root of a tree.

A tree is a connected undirected graph without cycles. A rooted tree is a tree with a selected vertex, which is called the root.

The tree is specified by an array of parents pp containing n numbers: pi is a parent of the vertex with the index ii. The parent of a vertex u is a vertex that is the next vertex on the shortest path from u to the root. For example, on the simple path from 5 to 3 (the root), the next vertex would be 1, so the parent of 55 is 11.

The root has no parent, so for it, the value of pi is i (the root is the only vertex for which pi=i).

Find such a set of paths that:

  • each vertex belongs to exactly one path, each path can contain one or more vertices;
  • in each path each next vertex — is a son of the current vertex (that is, paths always lead down — from parent to son);
  • number of paths is minimal.

For example, if n=5 and p=[3,1,3,3,1], then the tree can be divided into three paths:

  1. 3→1→5 (path of 3 vertices),
  2. 4 (path of 1 vertices).
  3. 2 (path of 1 vertices).

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B3SXPaGF-1652876022310)(https://espresso.codeforces.com/698e7b2721c55613a4aa03e1cdbc043c74106981.png)]

Example of splitting a root tree into three paths for n=5, the root of the tree — node 3.
Input

The first line of input data contains an integer t (1≤t≤10000) — the number of test cases in the test.

Each test case consists of two lines.

The first of them contains an integer n (1≤n≤200000). It is the number of vertices in the tree.

The second line contains nn integers p1,p2,…,pn (1≤pi≤n). It is guaranteed that the pp array encodes some rooted tree.

It is guaranteed that the sum of the values n over all test cases in the test does not exceed 200000.

Output

For each test case on the first line, output an integer mm — the minimum number of non-intersecting leading down paths that can cover all vertices of the tree.

Then print mm pairs of lines containing path descriptions. In the first of them print the length of the path, in the second — the sequence of vertices specifying that path in the order from top to bottom. You can output the paths in any order.

If there are several answers, output any of them.

Example

input
6
5
3 1 3 3 1
4
1 1 4 1
7
1 1 2 3 4 5 6
1
1
6
4 4 4 4 1 2
4
2 2 2 2
output
3
3
3 1 5
1
2
1
4

2
2
1 2
2
4 3

1
7
1 2 3 4 5 6 7

1
1
1

3
3
4 1 5
2
2 6
1
3

3
2
2 1
1
3
1
4
//本题是从叶子节点开始遍历,输出最少的路径数可以遍历完这棵树。
//最小的路径数就是这棵树拥有的叶子节点的个数。
//可以每个叶子节点从下往上搜寻,遍历过的节点就标记,直到将所有的节点遍历完成。第一眼看到觉得像并查集,但不是。
代码
#include <iostream>
#include <vector>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
bool vis[200010],fa[200010];//创建两个数组分别存放是否遍历与父节点
int f[200010];
void fin()
{
	memset(vis,false,sizeof(vis));	//每次调用都需要重新赋值
	memset(fa,false,sizeof(fa));
	int len,sum=0;
	cin>>len;
	for(int i=1;i<=len;i++)
	{
		cin>>f[i];
		if(!fa[f[i]])
		{
			fa[f[i]]=1;//如果为父节点,标记为1
			sum++;
		}
	}
		if(len>sum)cout<<len-sum<<endl;//叶子结点的个数
		else cout<<1<<endl;//特判:如果只有一个
	for(int i=1;i<=len;i++)
	{
		int flag=0;
		vector<int>v;
		if(!fa[i]||len==1)//如果循环遍历到的点是叶子节点,则开始往上搜寻                  
		{				  //还有一个特判,如果len=1,开始搜寻
			int now=i;
			while(!vis[now]) //
		{
			flag=1;      
			v.push_back(now);
			vis[now]=1;//遍历过就记录下来
			now=f[now];//搜寻父节点知道根节点。
		}
		if(flag)
		{
			cout<<v.size()<<endl;
			for(int j=v.size()-1;j>=0;j--)//倒序输出
			{
				cout<<v[j]<<" ";
			}cout<<endl;
		}
		}
	}
}

int main()
{
	cin>>n;
	while(n--)
	{
		fin();
		cout<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值