zoukankan      html  css  js  c++  java
  • ZOJ 3963:Heap Partition(贪心+set+并查集)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3963

    题意:给出一个n个数的序列,可以在其中找一个子序列建堆,并且堆中的父亲结点j和孩子结点i满足sj ≤ si and j < i。问要分配所有的数到堆里面,最少可以建多少个堆。

    思路:对于每一个数,如果前面有小于等于它的数并且那个数的左右孩子还没满,那么就可以放在它的下面。考虑最优情况,就应该是每次插入到左右孩子还没满的,并且小于等于当前枚举的数的最大的数,然后插入到这个数后面。

    因此可以用set来保存结点,每次都二分查找一下,如果没找到就建新的堆,找到了就插在它后面。

    可以用并查集来保存关系。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define N 100010
     4 struct node {
     5     int val, id, cnt;
     6     bool operator < (const node &rhs) const {
     7         if(rhs.val != val) return val < rhs.val;
     8         if(rhs.id != id) return id > rhs.id; // 大的id优先,因为val相同的话,要使得二分可以返回val
     9         return cnt > rhs.cnt;
    10     }
    11 };
    12 int fa[N], a[N];
    13 set<node> se;
    14 vector<int> ans[N];
    15 
    16 int Find(int x) { if(x == fa[x]) return x; return fa[x] = Find(fa[x]); }
    17 
    18 int main() {
    19     int t; scanf("%d", &t);
    20     while(t--) {
    21         int n; scanf("%d", &n);
    22         se.clear(); int k = 0;
    23         for(int i = 1; i <= n; i++) scanf("%d", &a[i]), a[i] = -a[i], fa[i] = i;
    24         for(int i = 1; i <= n; i++) {
    25             node now = (node) { a[i], i, 2 };
    26             set<node>::iterator it = se.lower_bound(now);
    27             // lower_bound返回大于等于now的元素,设成负数,可以变成返回小于等于now的元素
    28             if(it != se.end()) {
    29                 int x = it->val, y = it->id, z = it->cnt;
    30                 se.erase(it);
    31                 if(z - 1) se.insert((node) {x, y, z - 1});
    32                 fa[i] = Find(y);
    33             }
    34             se.insert(now);
    35         }
    36         for(int i = 1; i <= n; i++) if(fa[i] == i) ans[i].clear(), k++;
    37         for(int i = 1; i <= n; i++) ans[Find(i)].push_back(i);
    38         printf("%d
    ", k);
    39         for(int i = 1; i <= n; i++) {
    40             if(fa[i] != i) continue;
    41             printf("%d", ans[i].size());
    42             for(int j = 0; j < ans[i].size(); j++) printf(" %d", ans[i][j]);
    43             puts("");
    44         }
    45     }
    46     return 0;
    47 }
  • 相关阅读:
    JobTracker作业启动过程分析
    结构体传参
    getchar()
    char *a与char a[n]的区别
    EOF NULL 之间的区别
    现代方法第15章第三节的程序
    交换机console口连接
    undefined reference问题总结
    二维数组与指针
    数组作为参数传递的时候,被调用的函数内无法计算出数组的大小
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6759889.html
Copyright © 2011-2022 走看看