Find the answer

2019 Multi-University Training Contest 3

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=6609

题意:给一个序列, 对于第i个元素,要将前在前i个中取出k个数再和第i个数一起求和,将剩下的去除,对每个i要求k最大且和不超过m,即去除的数字个数最少且其余数字加起来小于等于m,对每个i输出它前面需要去除的数字个数,由于数据范围较大,需要进行离散化

思路:线段树+离散化

对于每个i,将其前面的i-1个元素根据离散化后的位置放到线段树里维护一个区间和以及区间个数,对每个区间总和小于m-a[i]的直接将区间个数计入答案,对于大于的继续向下查找,最后统计答案,用i-1-答案就是要去掉的个数,注意输出格式,不知道为啥最后一个数后面没有空格会PE。。。。。

//
// Created by mile on 2019/7/29.
//
//HDU多校2019 Day3 T7
//离散化+线段树
//输出格式:每个数字后面有一个空格, 每行输出后面一个空格

#include <bits/stdc++.h>

#define lid id<<1
#define rid id<<1|1
using namespace std;
typedef long long ll;
const int maxn = 200005;

struct Num {
    int cnt, val, id;
};

struct Node {
    int l, r, id, count;
    ll sum;
};

bool cmp1(Num a, Num b) {
    return a.val == b.val ? a.id < b.id : a.val < b.val;
}

bool cmp2(Num a, Num b) {
    return a.id < b.id;
}

struct SegmentTree {
    ll n, m;
    Num num[maxn];
    Node tr[maxn<<2];

    void init(int n, int m) {
        this->n = n, this->m = m;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &num[i].val);
            num[i].id = i;
        }
        sort(num+1, num+n+1, cmp1);
        for(int i = 1; i <= n; i++) num[i].cnt = i;
        sort(num+1, num+n+1, cmp2);
        build(1, 1, n);
    }

    void build(int id, int l, int r) {
        tr[id].l = l, tr[id].r = r;
        tr[id].sum = tr[id].count = 0;
        if(tr[id].l == tr[id].r) {
            return ;
        }
        int mid = (l+r)>>1;
        build(lid, l, mid);
        build(rid, mid+1, r);
        tr[id].sum = tr[lid].sum + tr[rid].sum;
    }

    void update(int id, int pos, int cnt) {
        if(tr[id].l == tr[id].r && tr[id].l == pos) {
            tr[id].sum = num[cnt].val; tr[id].count = 1;
            return ;
        }
        int mid = (tr[id].l + tr[id].r)>>1;
        if(pos <= mid) update(lid, pos, cnt);
        else update(rid, pos, cnt);
        tr[id].sum = tr[lid].sum+tr[rid].sum;
        tr[id].count = tr[lid].count+tr[rid].count;
    }

    int query(int id, ll sum) {
        if(tr[id].sum <= sum) return tr[id].count;
        if(tr[id].l == tr[id].r) return tr[id].sum <= sum;
        if(tr[lid].sum >= sum) return query(lid, sum);
        else return tr[lid].count+query(rid, sum-tr[lid].sum);
    }

    void solve() {
        for(int i = 1; i <= n; i++) {
            printf("%d ",i-1-query(1, m-num[i].val));
            update(1,num[i].cnt, num[i].id);
        }
        puts("");
    }
};

SegmentTree tree;


int main()
{
    int Q;
    scanf("%d", &Q);
    while(Q--) {
        ll n, m;
        scanf("%lld%lld", &n, &m);
        tree.init(n, m);
        tree.solve();
    }
    return 0;
}
View Code

  

猜你喜欢

转载自www.cnblogs.com/mile-star/p/11267416.html
今日推荐