zoj 3963 heap partion

https://vjudge.net/problem/ZOJ-3963

题意:

给出一个数列,可以用这个数列构造一种二叉树,这个二叉树满足数的下标 i <= j,并且 si <= sj,si是sj的父亲,问给出的数列可以构造多少棵这样的二叉树。

思路:

这题赛上没有写出来,看了题解之后给补的。

首先,通过这题学到了,memset初始化数组有时是会造成超时的。set的upper_bound(x)这个函数,它返回set中大于x的第一个元素的位置(注意是大于,不是大于等于)。

于是,这题就是贪心加set。贪心指的是对于当前的输入的x,在前面找到小于等于它的数,如果说没有找到,那么就把这个数插入,作为一棵新的树的根。如果说找到了,那么就把这个点插入这棵树,并且把这个数可插入的数量减1,当数量为0的时候就不能再插入了。具体看看注释。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <vector>
  4 #include <set>
  5 #include <algorithm>
  6 using namespace std;
  7 
  8 int num,node[100005],cnt[100005];//node保存节点x的编号,cnt数组表示每个节点能插入的剩下的位置
  9 
 10 vector<int> ans[100005];//ans保存答案
 11 set<int> s;
 12 
 13 void solve(int x,int pos)
 14 {
 15     set<int>::iterator it;
 16 
 17     it = s.upper_bound(x);
 18 
 19     if (it == s.begin())//x是最小的,所以选择插入
 20     {
 21         s.insert(x);
 22 
 23         cnt[x] = 2;//一开始有两个空位
 24 
 25         node[x] = num;
 26 
 27         ans[node[x]].push_back(pos);
 28 
 29         num++;
 30     }
 31     else
 32     {
 33         --it;//因为是大于x的位置,所以要--
 34 
 35         if (x == (*it))//相等,就不用插入,旧的元素
 36         {
 37 
 38             cnt[x]++;//相当于是加了2个位置,然后自己又占了一个
 39 
 40             ans[node[x]].push_back(pos);
 41         }
 42         else
 43         {
 44             node[x] = node[*it];
 45 
 46             cnt[*it]--;
 47 
 48             if (cnt[*it] == 0) s.erase(*it);//没有位置了,删除
 49 
 50             cnt[x] = 2;//新的元素
 51 
 52             s.insert(x);//后面插入是防止迭代器改变
 53 
 54             ans[node[x]].push_back(pos);
 55         }
 56     }
 57 }
 58 int main()
 59 {
 60     int t;
 61 
 62     scanf("%d",&t);
 63 
 64     while (t--)
 65     {
 66 
 67         s.clear();
 68 
 69         num = 0;
 70 
 71         int n;
 72 
 73         scanf("%d",&n);
 74 
 75         for (int i = 0;i <= n;i++)
 76         {
 77             node[i] = cnt[i] = 0;
 78             ans[i].clear();//说了n的总和不超过2 * 10 ^ 6,用memeset反而会超时
 79         }
 80 
 81         for (int i = 1;i <= n;i++)
 82         {
 83             int x;
 84 
 85             scanf("%d",&x);
 86 
 87             solve(x,i);
 88         }
 89 
 90         printf("%d\n",num);
 91 
 92         for (int i = 0;i < num;i++)
 93         {
 94             int sz = ans[i].size();
 95 
 96             printf("%d",sz);
 97 
 98             for (int j = 0;j < sz;j++)
 99             {
100                 printf(" %d",ans[i][j]);
101             }
102 
103             printf("\n");
104         }
105     }
106 
107     return 0;
108 }

 

posted @ 2017-07-23 20:47  qrfkickit  阅读(224)  评论(0编辑  收藏  举报