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 }
时间: 2024-10-13 04:10:51

zoj 3963 heap partion的相关文章

zoj 3963 Heap Partition(贪心)

Heap Partition Time Limit: 2 Seconds      Memory Limit: 65536 KB      Special Judge 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 se

ZOJ 3963 Heap Partition(multiset + stl自带二分 + 贪心)题解

题意:给你n个数字s1~sn,要你把它们组成一棵棵二叉树,对这棵二叉树来说,所有节点来自S,并且父节点si<=子节点sj,并且i<j,问你树最少几棵二叉数.树 思路:贪心.我们往multiset加还能加子节点的节点,二分查找一个个大于等于当前插入节点的节点,然后插入,若找不到则重新建一棵树. 没想到set自带lower_bound(),第一次迭代器遍历TLE就想着手动写二分...然后发现自带二分... 代码: #include<iostream> #include<stdio

ZOJ - 2243 - Binary Search Heap Construction

先上题目: Binary Search Heap Construction Time Limit: 5 Seconds      Memory Limit: 32768 KB Read the statement of problem G for the definitions concerning trees. In the following we define the basic terminology of heaps. A heap is a tree whose internal n

左偏树(Leftist Heap/Tree)简介及代码

左偏树是一种常用的优先队列(堆)结构.与二叉堆相比,左偏树可以高效的实现两个堆的合并操作. 左偏树实现方便,编程复杂度低,而且有着不俗的效率表现. 它的一个常见应用就是与并查集结合使用.利用并查集确定两个元素是否在同一集合,利用左偏树确定某个集合中优先级最高的元素. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 template <class T> 6 struct H

ZOJ 2724 Windows Message Queue

A - Windows Message Queue(10.2.1)) Crawling in process... Crawling failed Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Description Message queue is the basic fundamental of windows system. For each process, the system ma

zoj 2334 Monkey King

Monkey King ZOJ - 2334 题目大意:有n个猴子,一开始每个猴子只认识自己.每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害.如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了,不打不相识嘛.现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值. /* 左偏树模板题,包括合并,删除操作 */ #include<iostream> #

ZOJ 3946 Highway Project 贪心+最短路

题目链接: http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=3946 题解: 用dijkstra跑单元最短路径,如果对于顶点v,存在一系列边(ui,v)使得dis[v]最小(dis[v]表示0到v的距离).这些边能且只能选一条,那么我们自然应该选cost最小的那个边了. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #inc

通用的最小堆(最大堆)D-ary Heap

听说有一种最小(大)堆,不限于是完全二叉树,而是完全D叉树,名为D-ary Heap(http://en.wikipedia.org/wiki/D-ary_heap).D可以是1,2,3,4,100,对于优先队列该有的功能都没有问题. 动手写一个D-ary Heap,应该不难.简单起见,不考虑像STL一样通过template传入Comp类,下面的实现要求T类型重载了operator <和operator >. template<class T> class DaryHeap { s

概率dp ZOJ 3640

Help Me Escape Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Practice ZOJ 3640 Appoint description:  System Crawler  (2014-10-22) Description Background     If thou doest well, shalt thou not be accepted? an