T-decomposition(CF-237D)

Problem Description

You've got a undirected tree s, consisting of n nodes. Your task is to build an optimal T-decomposition for it. Let's define a T-decomposition as follows.

Let's denote the set of all nodes s as v. Let's consider an undirected tree t, whose nodes are some non-empty subsets of v, we'll call them xi . The tree t is a T-decomposition of s, if the following conditions holds:

  • the union of all xi equals v;
  • for any edge (a, b) of tree s exists the tree node t, containing both a and b;
  • if the nodes of the tree t xi and xj contain the node a of the tree s, then all nodes of the tree t, lying on the path from xi to xj also contain node a. So this condition is equivalent to the following: all nodes of the tree t, that contain node a of the tree s, form a connected subtree of tree t.

There are obviously many distinct trees t, that are T-decompositions of the tree s. For example, a T-decomposition is a tree that consists of a single node, equal to set v.

Let's define the cardinality of node xi as the number of nodes in tree s, containing in the node. Let's choose the node with the maximum cardinality in t. Let's assume that its cardinality equals w. Then the weight of T-decomposition t is value w. The optimal T-decomposition is the one with the minimum weight.

Your task is to find the optimal T-decomposition of the given tree s that has the minimum number of nodes.

Input

The first line contains a single integer n (2 ≤ n ≤ 105), that denotes the number of nodes in tree s.

Each of the following n - 1 lines contains two space-separated integers ai, bi (1 ≤ ai, bi ≤ n; ai ≠ bi), denoting that the nodes of tree s with indices ai and bi are connected by an edge.

Consider the nodes of tree s indexed from 1 to n. It is guaranteed that s is a tree.

Output

In the first line print a single integer m that denotes the number of nodes in the required T-decomposition.

Then print m lines, containing descriptions of the T-decomposition nodes. In the i-th (1 ≤ i ≤ m) of them print the description of node xi of the T-decomposition. The description of each node xi should start from an integer ki, that represents the number of nodes of the initial tree s, that are contained in the node xi. Then you should print ki distinct space-separated integers — the numbers of nodes from s, contained in xi, in arbitrary order.

Then print m - 1 lines, each consisting two integers pi, qi (1 ≤ pi, qi ≤ m; pi ≠ qi). The pair of integers pi, qi means there is an edge between nodes xpi and xqi of T-decomposition.

The printed T-decomposition should be the optimal T-decomposition for the given tree s and have the minimum possible number of nodes among all optimal T-decompositions. If there are multiple optimal T-decompositions with the minimum number of nodes, print any of them.

Examples

Input

2
1 2

Output

1
2 1 2

Input

3
1 2
2 3

Output

2
2 1 2
2 2 3
1 2

Input

4
2 1
3 1
4 1

Output
3
2 2 1
2 3 1
2 4 1
1 2
2 3

题意:

有一个编号从 1~n 的无向树 s,现在给出 n-1 条边,将所有点的集合记为 V,V 的非空子集记为 Xi

当满足下列三个条件时:所有的 Xi 的并集等于 V、树 s 的任意一条边 (a,b) 都存在一个结点 t 包含 a,b、树 t 的所有结点包含树 s 的结点 a 形成树的连通子树,称为一个 T-分解

现在将结点 Xi 的权重定义为 T-分解中一个结点中原来树的结点中点编号最大的编号,构造一个最小权重的 T 分解

首先输出一个数 m 代表最佳 T 分解的结点个数,然后输出 m 个点的编号,再输出最佳 T 分解的 m-1 条边

思路:

题意十分复杂,但读明白了这个题就十分简单,题目本质上就是构造一棵新的树,使得树上的新结点是之前树上的某条边,权值是新点中原点里编号最大的那个的编号,并且构建出的树权值最小

由于要求权值最小,那么我们尽量让新点中最大的那个编号数更小,考虑每两个点组成一个新结点,这样一来,可以保证构建出的新树是权值最小的

考虑新树的点,由于原来的树有 n-1 条边,那么新树就有 n-1 个点,每个点是原树的一条边,每输入一条边,就直接输出对应的点的编号

再考虑新树的边,在输入的时候,将原来的边的点与当前点的编号 i 分别构建一条新边即可,最后只需要将相邻两边输出即可

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
const int MOD = 1E9+7;
const int N = 500000+5;
const int dx[] = {-1,1,0,0,-1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;
vector<int> G[N];
int main(){
    int n;
    scanf("%d",&n);

    printf("%d\n",n-1);//新树n-1个点
    for(int i=1;i<=n-1;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        printf("2 %d %d\n",x,y);//新树的点

        x--;
        y--;
        G[x].push_back(i);
        G[y].push_back(i);
    }

    for(int i=0;i<=n-1;i++)
        for(int j=0;j<G[i].size()-1;j++)
            printf("%d %d\n",G[i][j],G[i][j+1]);

    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值