1. 程式人生 > >ZOJ 3963 Heap Partition(multiset + stl自帶二分 + 貪心)題解

ZOJ 3963 Heap Partition(multiset + stl自帶二分 + 貪心)題解

題意:給你n個數字s1~sn,要你把它們組成一棵棵二叉樹,對這棵二叉樹來說,所有節點來自S,並且父節點si<=子節點sj,並且i<j,問你樹最少幾棵二叉數、樹

思路:貪心。我們往multiset加還能加子節點的節點,二分查詢一個個大於等於當前插入節點的節點,然後插入,若找不到則重新建一棵樹。

沒想到set自帶lower_bound(),第一次迭代器遍歷TLE就想著手動寫二分...然後發現自帶二分...

程式碼:

#include<iostream>
#include<stdio.h>
#include<cmath>
#include
<string> #include<queue> #include<set> #include<vector> #include<string.h> #include<algorithm> typedef long long int ll; using namespace std; const int maxn = 1e5 + 5; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; vector<int> G[maxn]; struct node{ int
id, sz, num; }; struct compare{ bool operator () (node a, node b){ return a.sz > b.sz; } }; node add(int id, int sz){ node a; a.id = id , a.sz = sz, a.num = 0; return a; } multiset<node, compare> q; int main(){ int T, a; scanf("%d", &T); while(T--){ q.clear();
int n; scanf("%d", &n); scanf("%d", &a); int cnt = 2; q.insert(add(1, a)); G[1].clear(); G[1].push_back(1); node p; for(int i = 2; i <= n; i++){ scanf("%d" ,&a); multiset<node>::iterator it; p.sz = a; it = q.lower_bound(p); if(it == q.end()){ q.insert(add(cnt, a)); G[cnt].clear(); G[cnt].push_back(i); cnt++; } else{ p = *it; q.erase(it); p.num++; if(p.num < 2) q.insert(p); q.insert(add(p.id, a)); G[p.id].push_back(i); } } printf("%d\n", cnt - 1); for(int i = 1; i < cnt; i++){ int len = G[i].size(); printf("%d", len); for(int j = 0; j < len; j++) printf(" %d", G[i][j]); printf("\n"); } } return 0; }