题干:

A sequence S = {s1, s2, ..., sn} is called heapable if there exists a binary tree Twith n nodes such that every node is labelled with exactly one element from the sequence S, and for every non-root node si and its parent sj, sj ≤ si and j < ihold. Each element in sequence S can be used to label a node in tree T only once.

Chiaki has a sequence a1, a2, ..., an, she would like to decompose it into a minimum number of heapable subsequences.

Note that a subsequence is a sequence that can be derived from another sequence by deleting some elements without changing the order of the remaining elements.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contain an integer n (1 ≤ n ≤ 105) — the length of the sequence.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ n).

It is guaranteed that the sum of all n does not exceed 2 × 106.

Output

For each test case, output an integer m denoting the minimum number of heapable subsequences in the first line. For the next m lines, first output an integer Ci, indicating the length of the subsequence. Then output Ci integers Pi1, Pi2, ..., PiCiin increasing order on the same line, where Pij means the index of the j-th element of the i-th subsequence in the original sequence.

Sample Input

4
4
1 2 3 4
4
2 4 3 1
4
1 1 1 1
5
3 2 1 4 1

Sample Output

1
4 1 2 3 4
2
3 1 2 3
1 4
1
4 1 2 3 4
3
2 1 4
1 2
2 3 5

Hint

题目大意:

用给出的数列a1,a2,a3....an构造二叉树,满足对于下标i和j,有i<j 且ai<=aj满足ai是aj的父节点,问最少需要构造几棵树,并输出每棵树的元素个数和每个元素对应原数组的下标。

解题报告:

从前往后在线处理,用set维护可用节点的权值val和集合编号id和可用子节点数res,每一次贪心找到小于该值的最大的那个节点,插入到其子节点并且维护set中元素(也就是这个元素的根节点的res值),如果找不到该元素,就新开一个集合记录就可以了。注意代码姿势、、、另外因为这题会有重复的val出现,所以需要multiset不能set。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
int f[MAX];
struct Node {int val;int res;int id;Node(){}Node(int val,int res,int id):val(val),res(res),id(id){}bool operator<(const Node & b) const {return val < b.val;}
} ;
multiset<Node> ss;
int main()
{int t,n;cin>>t;while(t--) {int tot = 0;ss.clear();scanf("%d",&n);for(int x,i = 1; i<=n; i++) {scanf("%d",&x);auto it = ss.lower_bound(Node(x,0,0));if((int)ss.size()==0 || (it == ss.begin() && (*it).val > x)) {                tot++;f[i] = tot;ss.insert(Node(x,2,f[i]));}else {if(it == ss.end()) --it;auto cur = *it;if(cur.val > x) --it;//找到第一个小于等于该值的。 cur = *it;ss.erase(it);f[i] = cur.id;cur.res--;ss.insert(Node(x,2,f[i]));if(cur.res > 0) ss.insert(cur);}}vector<int> vv[tot+1];for(int i = 1; i<=n; i++) {vv[f[i]].push_back(i);}printf("%d\n",tot);for(int i = 1; i<=tot; i++) {int up = (int)vv[i].size();printf("%d ",up);for(int j = 0; j<up; j++) {printf("%d%c",vv[i][j],j == up-1 ? '\n' :' ');}}}return 0 ;
}

WA的部分:(这样写就WA了,,因为你没有更新set中的值,只是在外面更改了cur)

         else {if(it == ss.end()) --it;auto cur = *it;if(cur.val > x) --it;//找到第一个小于等于该值的。 cur = *it;f[i] = cur.id;cur.res--;ss.insert(Node(x,2,f[i]));if(cur.res == 0) ss.erase(it);}

AC代码2:(set维护下标)

思路就是先从大到小排序,这样就不需要考虑值的大小问题了,这样只需要考虑下标要求的一个小于号,这一点我们可以用set来维护。想法是这样的,相当于我们每次都插入这一个根结点,然后看set里面能否有节点可以当他的孩子节点,注意因为值是由大到小排好序的,所以set里面理论上拿哪一个值都不影响结果的正确性,但是因为这题还需要下标的关系,所以我们还需要二分查找一下合法的下标(因为我们能用的比我们大的值,要求下标也比我大,所以我需要lower或者upper查询(其实这里都一样,因为位置都是unique的),得到我可以用来当孩子结点的下标(一共可以选两个当孩子,选哪个都无所谓,只需要下标满足就可以了),如果实在没有可以当下标的(it == ss.end()),那就只能break掉了,相当于只选择一个当孩子节点。),并将该下标所属的集合改成当前遍历的那个数为根节点的集合。一次类推,最后并查集输出答案就行了。其实还是相当于一个逆向思维,从叶子结点往上构造。但是较AC代码1来说,这个比较难想。

相应的set中从大到小排序,pair从小到大排序,应该也可以做。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
set<int> ss;
PII p[MAX];
int f[MAX],tot,n;
int main() {int t;cin>>t;while(t--) {scanf("%d",&n);ss.clear();tot=0;for(int i = 1; i<=n; i++) f[i] = i;for(int x,i = 1; i<=n; i++) {scanf("%d",&x);p[i] = pm(x,i);}sort(p+1,p+n+1,greater<PII>());for(int i = 1; i<=n; i++) {int pos = p[i].S;for(int j = 0; j<2; j++) {auto it = ss.lower_bound(pos);if(it == ss.end()) break;f[*it] = pos;ss.erase(it);}ss.insert(pos);}vector<int> vv[n+1];for(int i = 1; i<=n; i++) {if(f[i] != i) f[i] = f[f[i]];//这里因为每一个f[i]一定是前面的值,并且一定已经是更新好的,所以不需要并查集了,只需要一步压缩就可以了。vv[f[i]].push_back(i);}for(int i = 1; i<=n; i++) {if(vv[i].size()) tot++;}printf("%d\n",tot);for(int i = 1; i<=n; i++) {if(vv[i].empty()) continue;int up = (int)vv[i].size();printf("%d ",up);for(int j = 0; j<up; j++) {printf("%d%c",vv[i][j],j == up-1 ? '\n' :' ');}}}return 0 ;
}

【ZOJ - 3963】Heap Partition (STLset,二叉树的性质,构造,贪心,思维)相关推荐

  1. 【HDU - 5744 】Keep On Movin (回文串性质,贪心思维,不是水题)

    题干: Professor Zhang has kinds of characters and the quantity of the ii-th character is aiai. Profess ...

  2. c++用二叉树表示代数表达式_C语言:数据结构-二叉树的定义和基本术语和二叉树的性质...

    二叉树的定义和基本术语 (1)二叉树的定义 二叉树(Binary Tree):每个结点至多有两棵子树,且子树有左.右之分.在二叉树中不含度数大于2的结点. 二叉树的递归定义为:二叉树或者是一棵空树,或 ...

  3. 再谈二叉树(二叉树概念,二叉树的性质,二叉树的存储结构)

    树的概念 树的概念 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合.把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的.它具有以下的特点 ...

  4. 数据结构(一)——二叉树的性质与两种遍历方法

    二叉树 二叉树的存储 1. 二叉树的性质 1.1满二叉树 1.2完全二叉树 2.二叉树的存储结构 二叉树的遍历 1.深度优先遍历 1.1先序遍历 1.2中序遍历 1.3后序遍历 二叉树的存储 1. 二 ...

  5. 树的常见概念,二叉树的性质

    什么是树 树是一种非线性数据结构,它是由n(n>=0)个有限结点组成的一个具有层次的关系集合.它有以下几个特点: List item有一个特殊的节点,称为根节点,根节点没有前驱节点 除根节点,其 ...

  6. 二叉树Ⅰ · 树型结构 · 二叉树 · 满二叉树 · 完全二叉树 · 二叉树的性质 · 二叉树的存储

    目录 一.树型结构(了解) 1.1 引入和特点 1.2 概念(重要) 1.3 树的表示形式(了解) 二.二叉树(重点) 2.1 概念 2.2 二叉树的基本形态 2.3 两种特殊的二叉树 满二叉树 完全 ...

  7. k叉树的性质_二叉树的性质总结.doc

    <二叉树的性质总结.doc>由会员分享,提供在线免费全文阅读可下载,此文档格式为doc,更多相关<二叉树的性质总结.doc>文档请在天天文库搜索. 1.一.二叉树的性质性质1 ...

  8. 二叉树的性质及其创建

    二叉树的性质 性质1 在二叉树的第i层上至多有2^(i-1)个结点(i>=1) 性质2 深度为k的二叉树至多有2^k-1个结点(k>=1) 性质3 对任意一棵二叉树,若终端结点数为n0,其 ...

  9. 二叉树相关性质以及数学证明

    性质一: 在二叉树中,设度为0的结点数为n0,度为2的结点数为n2,有n0=n2+1在二叉树中,设度为0的结点数为n_0,度为2的结点数为n_2,有n_0=n_2+1在二叉树中,设度为0的结点数为n0 ...

最新文章

  1. COM和ATL学习方法
  2. android file 创建时间,获得文件的创建时间(精确到时分秒)
  3. Google Research新成果,让表格理解和检索更上一层楼!
  4. Gearman + Nodejs + MySQL UDF异步实现 MySQL 到 Redis 的数据同步
  5. 【C++面向对象】类的静态成员函数(static member functions)
  6. python case语句_高效使用Python字典,技巧都在这里!
  7. java读取配置文件
  8. Mutual Review
  9. 离开(切换)当前页面时改变页面title
  10. AJAX问题:如果SESSION丢失,会直接报错。
  11. 一步步实现 仿制Android LOL多玩盒子(二) 物品装备相关
  12. 从零开始学习CANoe(二)—— CANdb++ 创建 dbc文件
  13. Linux进程管理(redhat 8.0)
  14. Docker架设服务器系列
  15. 基因表达矩阵中排除表达量低的样本和基因
  16. c#如何使用webservice、存储过程及存储过程的创建(简单模仿类似QQ统计用户在线时间为例)
  17. JavaServer Faces 2.0 can not be installed解决方案
  18. 直播带货app源码,实现直播的秒开和优化
  19. 天气预报API,你想要的它都有
  20. Linux主机安全配置

热门文章

  1. 原生JS实现淡入淡出效果(fadeIn/fadeOut/fadeTo)
  2. Codeforces Round #413 C-Fountains 树状数组
  3. 简易计算器 java_终于写出一个简单的计算器了
  4. 5d4的白平衡模式_佳能5D4/5D3/6D2系列中高端单反相机和全画幅微单EOS R专题系列课程...
  5. 1037C. Equalize
  6. xpath中两个冒号_爬虫学习(5)—XPath
  7. dede plus ad js.php,织梦dedecms/plus/文件夹的功能介绍
  8. 3个阶段 项目征名_萧山日报数字报-蓝城萧立7大代建项目征名开启
  9. 求合体电脑版_网红界宋祖儿找年轻版言承旭当男友,一张合照收割大量cp粉?!...
  10. mysql增加最大连接数_mysql最大连接数怎么设置