稳定桌【权值线段树】

题目链接 51nod 1461 稳定桌


有一张桌子,有n个腿。第i根腿的长度是li。

现在要拿掉一些腿,使得桌子稳定,拿掉第i根腿需要di的能量。

稳定的条件是,假如拿掉若干条腿之后,桌子还有k个腿,那么长度最长的腿的数目要超过一半。比如桌子有5根腿,那么至少要有三根腿是最长的。另外,只有一根腿的桌子是稳定的,两个腿的桌子想要稳定,必需长度是一样的。

你的任务是拿掉若干腿,使得桌子稳定,并且所消耗的能量要最少。


  我们可以枚举是哪个“高度”最为这个最高高度。

  那么,高于这个最高高度的,就必须要减去了的,然后在剩下部分,我们可能还要减去一些点,使得这个高度超过一半,我们肯定减去的是最小的部分,所以用权值线段树充当一个可以维护前K小的和的堆。

  注意的是,假如第K小的时候有多个相同权值,要注意只用取K个,不要多取!

PS:此题卡Splay常数,给一组先逐个升序、再逐个降序的序列,就会让Splay摸不着头脑,不仅本身大常数,还被卡。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, root = 0, tot = 0, L[maxN], D[maxN], _UP = 0, sz[maxN] = {0};
ll ss[maxN] = {0};
vector<int> vt[maxN];
struct BIT_Tree
{
    ll sum[maxN << 2]; int num[maxN << 2];
    void update(int rt, int l, int r, int qx)
    {
        num[rt]++; sum[rt] += qx;
        if(l == r) return;
        int mid = HalF;
        if(qx <= mid) update(Lson, qx);
        else update(Rson, qx);
    }
    ll query(int rt, int l, int r, int kth)
    {
        if(l == r) return 1LL * kth * l;
        int mid = HalF;
        if(num[lsn] >= kth) return query(Lson, kth);
        else return query(Rson, kth - num[lsn]) + sum[lsn];
    }
} b;
int main()
{
    scanf("%d", &N);
    for(int i=1; i<=N; i++) { scanf("%d", &L[i]); _UP = max(_UP, L[i]); }
    for(int i=1; i<=N; i++) scanf("%d", &D[i]);
    for(int i=1; i<=N; i++) vt[L[i]].push_back(D[i]);
    for(int i=1, len; i<=_UP; i++)
    {
        len = (int)vt[i].size();
        ss[i] = ss[i - 1]; sz[i] = sz[i - 1] + len;
        for(int j=0; j<len; j++) ss[i] += vt[i][j];
    }
    ll ans = INF, tmp;
    for(int i=1, len, need_del; i<=_UP; i++)
    {
        len = (int)vt[i].size();
        if(!len) continue;
        tmp = ss[_UP] - ss[i];
        need_del = sz[i - 1] - len + 1;
        if(need_del > 0)
        {
            tmp += b.query(1, 1, 100000, need_del);
        }
        ans = min(ans, tmp);
        for(int j=0; j<len; j++) b.update(1, 1, 100000, vt[i][j]);
    }
    printf("%lld\n", ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值