题意: 给你n种树,以及它的高度,被砍掉的代价,以及它的数量,问你,砍掉一些树后,使得剩下的树中,最高的树的数量是剩下总数的一半 + 1 以上!
思路: 很明确,直接枚举,从最高的树往低的树枚举,然后用权值线段树来维护相应树的数量以及相应的代价!
因为没写过权值线段树的代码,所以到师傅那学了下,自己手敲了一遍,wa了几发,离散化下表忘记加1了,代码有点乱希望别介意!
#include
using namespace std;
const int maxn = 1e5 + 5;
const long long INF = 0xffffffffffffff;
struct node
{
long long num;
long long val;
}nodes[maxn<<2];
struct tree
{
long long height;
long long val;
long long num;
friend bool operator < (tree a, tree b)
{
return a.height > b.height;
}
}em[maxn];
//用于离散化
vector<long long> ve;
inline int getID(long long x)
{
return (lower_bound(ve.begin(), ve.end(), x) - ve.begin()) + 1;
}
void init()
{
ve.clear();
}
void PushUp(int root)
{
nodes[root].num = nodes[root<<1].num + nodes[root<<1|1].num;
nodes[root].val = nodes[root<<1].val + nodes[root<<1|1].val;
}
//建树
void Build(int root, int l, int r)
{
//记得每个节点都要初始化
nodes[root].num = nodes[root].val = 0;
if(l == r){
return ;
}
int mid = (l + r) >> 1;
Build(root<<1, l, mid);
Build(root<<1|1, mid + 1, r);
}
void add(int root, int l, int r, int k, long long val)
{
if(l == r){
nodes[root].num += val;
nodes[root].val += ve[l - 1] * val;
return ;
}
int mid = (l + r) >> 1;
if(k <= mid){
add(root<<1, l , mid, k, val);
}
else{
add(root<<1|1, mid + 1, r, k, val);
}
PushUp(root);
}
long long query(int root, int l, int r, long long neednum)
{
if(neednum <= 0) return 0; // 不用砍树了 当然返回0
if(l == r){
return ve[l - 1] * neednum;
}
int mid = (l + r) >> 1;
long long ans = 0;
if(neednum < nodes[root<<1].num){
ans += query(root<<1, l, mid, neednum);
}
else{
ans += nodes[root<<1].val;
ans += query(root<<1|1, mid + 1, r, neednum - nodes[root<<1].num);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
int n;
while(cin >> n){
init();
for(int i = 1; i <= n; i++){
cin >> em[i].height >> em[i].val >> em[i].num;
ve.push_back(em[i].val);
}
sort(em + 1, em + 1 + n);
sort(ve.begin(), ve.end());
ve.erase(unique(ve.begin(), ve.end()), ve.end());
Build(1, 1, n);
long long totnum = 0;
for(int i = 1; i <= n; i++){
totnum += em[i].num;
add(1, 1, n, getID(em[i].val), em[i].num); //离散化后把树的数量代价给加进去
}
long long ans = INF, now_num = 0, now_val = 0, nums = 0, vals = 0;
for(int i = 1; i <= n; i++){
now_num += em[i].num;
now_val += em[i].val * em[i].num;
if(i != n - 1 && em[i].height == em[i + 1].height){
add(1, 1, n, getID(em[i].val), -em[i].num);
continue;
}
add(1, 1, n, getID(em[i].val), -em[i].num); // 砍掉这类树
long long neednum = totnum - (now_num * 2 - 1); //比一半多
ans = min(ans, vals + query(1, 1, n, neednum));
vals += now_val;
totnum -= now_num;
now_val = now_num = 0;
if(vals > ans){
break;
}
}
cout << ans << endl;
}
return 0;
}