D. Vertical Paths

D. Vertical Paths

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

You are given a rooted tree consisting of nn vertices. Vertices are numbered from 11 to nn. 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 nn numbers: pipi is a parent of the vertex with the index ii. The parent of a vertex uu is a vertex that is the next vertex on the shortest path from uu to the root. For example, on the simple path from 55 to 33 (the root), the next vertex would be 11, so the parent of 55 is 11.

The root has no parent, so for it, the value of pipi is ii (the root is the only vertex for which pi=ipi=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=5n=5 and p=[3,1,3,3,1]p=[3,1,3,3,1], then the tree can be divided into three paths:

  1. 3→1→53→1→5 (path of 33 vertices),
  2. 44 (path of 11 vertices).
  3. 22 (path of 11 vertices).

 

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

Input

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

Each test case consists of two lines.

The first of them contains an integer nn (1≤n≤2⋅1051≤n≤2⋅105). It is the number of vertices in the tree.

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

It is guaranteed that the sum of the values nn over all test cases in the test does not exceed 2⋅1052⋅105.

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

Copy

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

Copy

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

题意:就是给你一个排列然后每个下标对应的元素是其下标的父节点,然后让你求出有几个不同的路径

这题先不管父子节点的类型先用vector存下每个节点能连接的数字

然后dfs,dfs中有三个自变量,第一个是由哪个节点来的,第二个是现在的状态即这个是第几条路径,第三个是这个节点的父亲节点;

然后相当与一个发散的过程我认为你可以认为成开花的过程,把这个点连接到的点都标上第一个子节点是当前这条路,这个点多连的点就是多的路,你可以对发散出去的点在进行dfs,相当于对每一个点都进行了dfs

最终在dfs的过程中找到了总的方案数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
const int N = 2e5+10;
#define ios                      \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0);
int root;
int cnt;	int n;
vector<int>v[N],ans[N];
void dfs(int rt,int num,int fa)
{
	int nn=0;
	ans[num].push_back(rt);
	for(int i=0;i<v[rt].size();i++)
	{
		int nx=v[rt][i];
		if(nx==fa)
		continue;
		nn++;
		if(nn>1)
		{
			dfs(nx,++cnt,rt);
		}
		else{
			dfs(nx,num,rt);
		}
	}
}
void solve()
{
	cin>>n;
	cnt=0;
    for(int i=1;i<=n;i++) {
        v[i].clear(),ans[i].clear();
    }
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		if(x==i) 
		root=x;
		else{
		v[x].push_back(i);
		v[i].push_back(x);			
		}

	}
	dfs(root,++cnt,-1);
 
    cout<<cnt<<"\n";
    for(int i=1; i<=cnt; i++){
        cout<<ans[i].size()<<"\n";
        for(auto t : ans[i]) cout<<t<<" ";
        cout<<"\n";
    }
    cout<<"\n";	
}
int main()
{
	ios;
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值