ZOJ - 3963 Heap Partition 贪心+线段树

A sequence S = {s1, s2, ..., sn} is called heapable if there exists a binary tree T with 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 < i hold. 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, ..., PiCi in 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

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

题解:因为每个数到最后肯定会用到,所以我们对于当前要形成的二叉树给他找子代的时候就找后面第一个比他大的就好。要注意的是,我们需要先找当前二叉树,子代没达到两个的,并且值最大的,因为我们要找尽可能多的点,所以先尽可能给值大的点找子代,找不到或者子代已经达到两个,该点就已达到最佳,然后继续找下一个即可。写的时候傻逼了,一个点找到一个子代之后,又找了一遍,这是不对的,因为自代的值比他大,所以应先找价值最大的!!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<stack>
#include<cmath>
#include<map>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+10;
struct node{
	int l,r;
	int maxx;
}tree[N<<2];
struct node1{
	int id;
	int x;
	int num;
	node1(){
	}
	node1(int id_,int x_,int num_):id(id_),x(x_),num(num_){
	}
	bool operator <(const node1 &xx)const 
	{
		return x<xx.x;
	}
};
int n,vis[N],len,a[N];
vector<int> v[N];
void build(int l,int r,int cur)
{
	tree[cur].l=l;
	tree[cur].r=r;
	if(l==r)
	{
		scanf("%d",&tree[cur].maxx);
		a[l]=tree[cur].maxx;
		return;
	}
	int mid=(r+l)>>1;
	build(l,mid,cur<<1);
	build(mid+1,r,cur<<1|1);
	tree[cur].maxx=max(tree[cur<<1].maxx,tree[cur<<1|1].maxx);
}
int cnt;
void query(int val,int pos,int cur)
{
	if(tree[cur].maxx<val||cnt!=-1) return;
	if(tree[cur].l==tree[cur].r)
	{
		cnt=tree[cur].l;
		tree[cur].maxx=-1;
		return;
	}
	if(tree[cur<<1].maxx>=val&&pos<=tree[cur<<1].r) query(val,pos,cur<<1);
	if(tree[cur<<1|1].maxx>=val) query(val,pos,cur<<1|1);
	tree[cur].maxx=max(tree[cur<<1].maxx,tree[cur<<1|1].maxx);
}
void update(int pos,int cur)
{
	if(tree[cur].l==tree[cur].r)
	{
		tree[cur].maxx=-1;
		return;
	}
	if(pos<=tree[cur<<1].r) update(pos,cur<<1);
	else update(pos,cur<<1|1);
	tree[cur].maxx=max(tree[cur<<1].maxx,tree[cur<<1|1].maxx);
}
int main()
{
	int T,x;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		build(1,n,1);
		len=0;
		for(int i=0;i<=n;i++)v[i].clear(),vis[i]=0;
		len=0;
		for(int i=1;i<=n;i++)
		{
			if(vis[i]) continue;
			v[len].push_back(i);
			update(i,1);
			priority_queue<node1> q;
			q.push(node1(i,a[i],0));
			
			while(!q.empty())
			{
				cnt=-1;
				node1 now=q.top();q.pop();
				query(now.x,now.id,1);
				if(cnt!=-1)
				{
					now.num++;
					vis[cnt]=1;
					v[len].push_back(cnt);
					q.push(node1(cnt,a[cnt],0));
					if(now.num<2) q.push(now);
				}
				
			}
			len++;
		}
		printf("%d\n",len);
		for(int i=0;i<len;i++)
		{
			printf("%d",v[i].size());
			sort(v[i].begin(),v[i].end());
			for(int j=0;j<v[i].size();j++)
				printf(" %d",v[i][j]);
			printf("\n");
		}
		
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/84555577