POJ2010---Moo University - Financial Aid(红黑树或优先队列)

                      Moo University - Financial Aid

Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 12380 Accepted: 3670

Description

Bessie noted that although humans have many universities they can attend, cows have none. To remedy this problem, she and her fellow cows formed a new university called The University of Wisconsin-Farmside,"Moo U" for short. 

Not wishing to admit dumber-than-average cows, the founders created an incredibly precise admission exam called the Cow Scholastic Aptitude Test (CSAT) that yields scores in the range 1..2,000,000,000. 

Moo U is very expensive to attend; not all calves can afford it.In fact, most calves need some sort of financial aid (0 <= aid <=100,000). The government does not provide scholarships to calves,so all the money must come from the university's limited fund (whose total money is F, 0 <= F <= 2,000,000,000). 

Worse still, Moo U only has classrooms for an odd number N (1 <= N <= 19,999) of the C (N <= C <= 100,000) calves who have applied.Bessie wants to admit exactly N calves in order to maximize educational opportunity. She still wants the median CSAT score of the admitted calves to be as high as possible. 

Recall that the median of a set of integers whose size is odd is the middle value when they are sorted. For example, the median of the set {3, 8, 9, 7, 5} is 7, as there are exactly two values above 7 and exactly two values below it. 

Given the score and required financial aid for each calf that applies, the total number of calves to accept, and the total amount of money Bessie has for financial aid, determine the maximum median score Bessie can obtain by carefully admitting an optimal set of calves. 
 

Input

* Line 1: Three space-separated integers N, C, and F 

* Lines 2..C+1: Two space-separated integers per line. The first is the calf's CSAT score; the second integer is the required amount of financial aid the calf needs 

Output

* Line 1: A single integer, the maximum median score that Bessie can achieve. If there is insufficient money to admit N calves,output -1. 

Sample Input

3 5 70
30 25
50 21
20 20
5 18
35 30

Sample Output

35

Hint

Sample output:If Bessie accepts the calves with CSAT scores of 5, 35, and 50, the median is 35. The total financial aid required is 18 + 30 + 21 = 69 <= 70. 

Source

USACO 2004 March Green

 

题意:

C个学生申报某大学,每个人都需要申请资助aid 元,每个人的报考分数为score分,现从中选出n个人录取(n保证是奇数),要求总资助不超过F元,且选出的n个人的分数的中位数最大,求此中位数。

解法一:优先队列

根据分数高低给数据排序,枚举中位数,用两个优先队列分别维护位置i左边最小的n/2个资助和位置i右边最小的n/2个资助

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue> 

using namespace std;
const int maxn=200005;
const int inf=0x3f3f3f3f;
typedef long long ll;

int n,m;
ll f,lmin[maxn],rmin[maxn];
struct node{
	ll sco,aid;
	node(int a=0,int b=0){
		sco=a;aid=b;
	}
	friend bool operator<(const node &a,const node &b){
		return a.aid<b.aid;
	}
}a[maxn];

bool cmp(node a,node b)
{
	return a.sco<b.sco;
}

priority_queue<node> que;

int main()
{
	scanf("%d %d %lld",&n,&m,&f);
	for(int i=1;i<=m;i++) scanf("%lld %lld",&a[i].sco,&a[i].aid);
	sort(a+1,a+m+1,cmp);
	
	//solve from left
	ll sum=0;
	for(int i=1;i<=m;i++){
		if(que.size()==n/2){
			que.push(a[i]);
			node tmp=que.top();que.pop();
			lmin[i]=sum;
			sum+=a[i].aid;sum-=tmp.aid;
		}else{
			que.push(a[i]);
			sum+=a[i].aid;
		}
	} 
	//solve from right
	sum=0;
	while(!que.empty()) que.pop();
	for(int i=m;i>=1;i--){
		if(que.size()==n/2){
			que.push(a[i]);
			node tmp=que.top();que.pop();
			rmin[i]=sum;
			sum+=a[i].aid;sum-=tmp.aid;
		}else{
			que.push(a[i]);
			sum+=a[i].aid;
		}
	}
	
	ll ans=-1;
	for(int i=n/2+1;i<=m-n/2;i++) if(lmin[i]+rmin[i]+a[i].aid<=f) ans=a[i].sco;
	printf("%lld\n",ans);
}

解法二:红黑树

由于poj不支持pb_ds库,所以直接上红黑树。

#include <cstdio>
#include <cctype>
#include <iostream>
#include <cassert>
#include <algorithm>
using namespace std;

template<typename T> class redblacktree {
    private:
        struct Node;

        Node* _root;    根节点位置
        Node* _hot; 临时维护的节点

        void init(T);
        void connect34(Node*, Node*, Node*, Node*, Node*, Node*, Node*);
        void SolveDoubleRed(Node*); 双红修正
        void SolveDoubleBlack(Node*);   //双黑修正
        Node* find(T, const int);   允许重复的查找
        Node* rfind(T, const int);  不允许重复的查找
        Node* findkth(int, Node*);
        int find_rank(T, Node*);

        void checkconnect(Node*);
        void previs(Node*, int);
        void invis(Node*, int);
        void postvis(Node*, int);

    public:
        redblacktree() : _root(NULL), _hot(NULL) {}
        struct iterator;
        iterator begin();
        iterator end();
        iterator rbegin();
        iterator rend();
        
        int rank(T);
        iterator insert(T);
        bool erase(T);
        int size();
        bool empty();
        iterator kth(int);   //返回第k大的迭代器
        iterator pre(T);   //小于T的最大的元素,即前驱
        iterator next(T);   //大于T的最小的元素,即后继

        void vis();
        void correctlyconnected();
};

template <typename T>
struct redblacktree<T>::Node {
    T val;  节点信息
    bool RBc;   节点颜色,若为true,则节点为Red;否则节点为Black.
    Node* fa;  父亲
    Node* ls;   左儿子
    Node* rs;   右儿子
    int s;      域

    friend Node* bro(Node* x){
        return (((x)->fa->ls == (x)) ? ((x)->fa->rs) : ((x)->fa->ls));
    }
    friend bool isls(Node* x){
        return ((x) != NULL && (x->fa) != NULL && (x)->fa->ls == (x));
    }
    friend bool isrs(Node* x){
        return ((x) != NULL && (x->fa) != NULL && (x)->fa->rs == (x));
    }

    Node(   T v = T(), bool RB = true,
            Node* f = NULL, Node* l = NULL, Node* r = NULL ,int ss = 1  )
        : val(v), RBc(RB), fa(f), ls(l), rs(r), s(ss) {}

    Node* succ() {      删除节点时用到的替代节点
        Node* ptn = rs;
        while(ptn->ls != NULL) {
            --(ptn->s);
            ptn = ptn->ls;
        }
        return ptn;
    }

    Node* left_node() {     直接前驱
        Node* ptn = this;
        if(ptn->ls) {
            ptn=ptn->ls;
            while(ptn->rs) ptn=ptn->rs;
        }
        else if(isrs(ptn)) ptn=ptn->fa;
        else{
            ptn=ptn->fa;
            while(ptn){
                if(isrs(ptn)){
                    ptn=ptn->fa;
                    break;
                }
                ptn=ptn->fa;
            }
        }
        return ptn;
    }

    Node* right_node() {    直接后继
        Node* ptn = this;
        if(ptn->rs) {
            ptn=ptn->rs;
            while(ptn->ls) ptn=ptn->ls;
        }
        else if(isls(ptn)) ptn=ptn->fa;
        else{
            ptn=ptn->fa;
            while(ptn){
                if(isls(ptn)){
                    ptn=ptn->fa;
                    break;
                }
                ptn=ptn->fa;
            }
        }
        return ptn;
    }

    void maintain() {   维护域s
        s = 1;
        if(ls) s += ls->s;
        if(rs) s += rs->s;
    }
};

template <typename T>
struct redblacktree<T>::iterator {
    private:
        Node* _real__node;
    public:
        iterator& operator++() {
            _real__node = _real__node->right_node();
            return *this;
        }

        iterator& operator--() {
            _real__node = _real__node->left_node();
            return *this;
        }

        const iterator operator++(int){
            iterator tmp=*this;
            _real__node=_real__node->right_node();
            return tmp;
        }
        const iterator operator--(int){
            iterator tmp=*this;
            _real__node=_real__node->left_node();
            return tmp;
        }

        bool operator!=(const iterator &other){
            return _real__node!=other._real__node;
        }

        T operator*() {
            return _real__node->val;
        }

        iterator(Node* node_nn = NULL) : _real__node(node_nn) {}
        iterator(iterator const& iter) : _real__node(iter._real__node) {}

};

template<typename T>
typename redblacktree<T>::iterator redblacktree<T>::begin(){
    Node* ptn=_root;
    while(ptn->ls) ptn=ptn->ls;
    return ptn;
}

template<typename T>
typename redblacktree<T>::iterator redblacktree<T>::end(){
    return iterator(NULL);
}

template<typename T>
typename redblacktree<T>::iterator redblacktree<T>::rbegin(){
    Node* ptn=_root;
    while(ptn->rs) ptn=ptn->rs;
    return ptn;
}

template<typename T>
typename redblacktree<T>::iterator redblacktree<T>::rend(){
    return iterator(NULL);
}

template <typename T> 
typename redblacktree<T>::iterator redblacktree<T>::insert(T v) {
    Node* ptn = find(v, 1);
    if(_hot == NULL) {
        init(v);
        return iterator(_root);
    }
    ptn = new Node(v, true, _hot, NULL, NULL, 1);
    if( _hot->val <= v  ) _hot->rs = ptn;
    else _hot->ls = ptn;
    SolveDoubleRed(ptn);
    return iterator(ptn);
}

template <typename T>
void redblacktree<T>::init(T v) {
    _root = new Node(v, false, NULL, NULL, NULL, 1);
}

template <typename T>
typename
redblacktree<T>::Node* redblacktree<T>::find(T v, const int op) {
    Node* ptn = _root;  从根节点开始查找
    _hot = NULL;    维护父亲节点
    while(ptn != NULL) {
        _hot = ptn;
        ptn->s += op;
        if(ptn->val > v) ptn = ptn->ls;
        else ptn = ptn->rs;
    }
    return ptn;
}

template <typename T>
typename
redblacktree<T>::Node* redblacktree<T>::rfind(T v, const int op) {
    Node* ptn = _root;
    _hot = NULL;
    while(ptn != NULL && ptn->val != v) {
        _hot = ptn;
        ptn->s += op;
        if(ptn->val > v) ptn = ptn->ls;
        else ptn = ptn->rs;
    }
    return ptn;
}

template <typename T>
void redblacktree<T>::SolveDoubleRed(Node* nn) {
    while((!(nn->fa)) || nn->fa->RBc) {
        if(nn == _root) {
            _root->RBc = false;
            return;
        }
        Node* pfa = nn->fa;
        if(!(pfa->RBc)) return;            No double-red
        Node* uncle = bro(nn->fa);
        Node* grdfa = nn->fa->fa;
        if(uncle != NULL && uncle->RBc) {   RR-2
            grdfa->RBc = true;
            uncle->RBc = false;
            pfa->RBc = false;
            nn = grdfa;
        } else {                            RR-1
            if(isls(pfa)) {
                if(isls(nn)) {
                    pfa->fa = grdfa->fa;
                    if(grdfa == _root) _root = pfa;
                    else if(grdfa->fa->ls == grdfa) grdfa->fa->ls = pfa;
                    else grdfa->fa->rs = pfa;
                    connect34(pfa, nn, grdfa, nn->ls, nn->rs, pfa->rs, uncle);
                    pfa->RBc = false;
                    grdfa->RBc = true;
                } else {
                    nn->fa = grdfa->fa;
                    if(grdfa == _root) _root = nn;
                    else if(grdfa->fa->ls == grdfa) grdfa->fa->ls = nn;
                    else grdfa->fa->rs = nn;
                    connect34(nn, pfa, grdfa, pfa->ls, nn->ls, nn->rs, uncle);
                    nn->RBc = false;
                    grdfa->RBc = true;
                }
            } else {
                if(isls(nn)) {
                    nn->fa = grdfa->fa;
                    if(grdfa == _root) _root = nn;
                    else if(grdfa->fa->ls == grdfa) grdfa->fa->ls = nn;
                    else grdfa->fa->rs = nn;
                    connect34(nn, grdfa, pfa, uncle, nn->ls, nn->rs, pfa->rs);
                    nn->RBc = false;
                    grdfa->RBc = true;
                } else {
                    pfa->fa = grdfa->fa;
                    if(grdfa == _root) _root = pfa;
                    else if(grdfa->fa->ls == grdfa) grdfa->fa->ls = pfa;
                    else grdfa->fa->rs = pfa;
                    connect34(pfa, grdfa, nn, uncle, pfa->ls, nn->ls, nn->rs);
                    pfa->RBc = false;
                    grdfa->RBc = true;
                }
            }
            return;
        }
    }
}

template <typename T>
void redblacktree<T>::connect34(    Node* nroot,    Node* nls,      Node* nrs,
                                    Node* ntree1,   Node* ntree2,   Node* ntree3,   Node* ntree4) {
    nls->ls = ntree1;
    if(ntree1 != NULL) ntree1->fa = nls;
    nls->rs = ntree2;
    if(ntree2 != NULL) ntree2->fa = nls;
    nrs->ls = ntree3;
    if(ntree3 != NULL) ntree3->fa = nrs;
    nrs->rs = ntree4;
    if(ntree4 != NULL) ntree4->fa = nrs;
    nroot->ls = nls;
    nls->fa = nroot;
    nroot->rs = nrs;
    nrs->fa = nroot;
    nls->maintain();
    nrs->maintain();
    nroot->maintain();
}

template <typename T>
typename redblacktree<T>::iterator redblacktree<T>::pre(T v) {
    Node* ptn = _root;
    while(ptn) {
        _hot = ptn;
        if(ptn->val < v) ptn = ptn->rs;
        else ptn = ptn->ls;
    }
    if(_hot->val < v) ptn = _hot;
    else ptn = _hot->left_node();
    return iterator(ptn);
}

template <typename T>
typename redblacktree<T>::iterator redblacktree<T>::next(T v) {
    Node* ptn = _root;
    while(ptn) {
        _hot = ptn;
        if(ptn->val > v) ptn = ptn->ls;
        else ptn = ptn->rs; 
    }
    if(_hot->val > v) ptn = _hot;
    else ptn = _hot->right_node();
    return iterator(ptn);
}

template <typename T>
typename
redblacktree<T>::iterator redblacktree<T>::kth(int rank) {
    return iterator(findkth(rank, _root));
}

template <typename T>
typename
redblacktree<T>::Node* redblacktree<T>::findkth(int rank, Node* ptn) {
    if(!(ptn->ls)) {
        if(rank == 1) {
            return ptn;
        } else {
            return findkth(rank - 1, ptn->rs);
        }
    } else {
        if(ptn->ls->s == rank - 1) return ptn;
        else if(ptn->ls->s >= rank) return findkth(rank, ptn->ls);
        else return findkth(rank - (ptn->ls->s) - 1, ptn->rs);
    }
}

template <typename T>
int redblacktree<T>::rank(T v) {
    return find_rank(v, _root);
}

template <typename T>
int redblacktree<T>::find_rank(T v, Node* ptn) {
    if(!ptn) return 1;
    else if(ptn->val >= v) return find_rank(v, ptn->ls);
    else return (1 + ((ptn->ls) ? (ptn->ls->s) : 0) + find_rank(v, ptn->rs));
}

template <typename T>
int redblacktree<T>::size() {
    if(_root==NULL) return 0;
    return _root->s;
}

template <typename T>
bool redblacktree<T>::empty() {
    return !_root;
}

template <typename T>
bool redblacktree<T>::erase(T v) {
    Node* ptn = rfind(v, -1);
    if(!ptn) return false;
    Node* node_suc;
    while(ptn->ls || ptn->rs) { 迭代寻找真后继
        if(!(ptn->ls)) {
            node_suc = ptn->rs;
        } else if(!(ptn->rs)) {
            node_suc = ptn->ls;
        } else {
            node_suc = ptn->succ();
        }
        --(ptn->s);
        ptn->val = node_suc->val;
        ptn = node_suc;
    }
    if(!(ptn->RBc)) {
        --(ptn->s);
        SolveDoubleBlack(ptn);
    }
    if(ptn == _root) {
        _root = NULL;
        delete ptn;
        return true;
    }
    if(ptn->fa->ls == ptn)
        ptn->fa->ls = NULL;
    else
        ptn->fa->rs = NULL;
    delete ptn;
    return true;
}

template <typename T>
void redblacktree<T>::SolveDoubleBlack(Node* nn) {
    while(nn != _root) {
        Node* pfa = nn->fa;
        Node* bthr = bro(nn);
        if(bthr->RBc) {                 BB-1
            bthr->RBc = false;
            pfa->RBc = true;
            if(_root == pfa) _root = bthr;
            if(pfa->fa) {
                if(pfa->fa->ls == pfa)
                    pfa->fa->ls = bthr;
                else
                    pfa->fa->rs = bthr;
            }
            bthr->fa = pfa->fa;
            if(isls(nn)) {
                connect34(bthr, pfa, bthr->rs, nn, bthr->ls, bthr->rs->ls, bthr->rs->rs);
            } else {
                connect34(bthr, bthr->ls, pfa, bthr->ls->ls, bthr->ls->rs, bthr->rs, nn);
            }
            bthr = bro(nn);
            pfa = nn->fa;
        }
        if(bthr->ls && bthr->ls->RBc) { BB-3
            bool oldRBc = pfa->RBc;
            pfa->RBc = false;
            if(pfa->ls == nn) {
                if(pfa->fa) {
                    if(pfa->fa->ls == pfa)
                        pfa->fa->ls = bthr->ls;
                    else
                        pfa->fa->rs = bthr->ls;
                }
                bthr->ls->fa = pfa->fa;
                if(_root == pfa) _root = bthr->ls;
                connect34(bthr->ls, pfa, bthr, pfa->ls, bthr->ls->ls, bthr->ls->rs, bthr->rs);
            } else {
                bthr->ls->RBc = false;
                if(pfa->fa) {
                    if(pfa->fa->ls == pfa)
                        pfa->fa->ls = bthr;
                    else
                        pfa->fa->rs = bthr;
                }
                bthr->fa = pfa->fa;
                if(_root == pfa) _root = bthr;
                connect34(bthr, bthr->ls, pfa, bthr->ls->ls, bthr->ls->rs, bthr->rs, pfa->rs);
            }
            pfa->fa->RBc = oldRBc;
            return;
        } else if(bthr->rs && bthr->rs->RBc) {  BB-3
            bool oldRBc = pfa->RBc;
            pfa->RBc = false;
            if(pfa->ls == nn) {
                bthr->rs->RBc = false;
                if(pfa->fa) {
                    if(pfa->fa->ls == pfa)
                        pfa->fa->ls = bthr;
                    else
                        pfa->fa->rs = bthr;
                }
                bthr->fa = pfa->fa;
                if(_root == pfa) _root = bthr;
                connect34(bthr, pfa, bthr->rs, pfa->ls, bthr->ls, bthr->rs->ls, bthr->rs->rs);
            } else {
                if(pfa->fa) {
                    if(pfa->fa->ls == pfa)
                        pfa->fa->ls = bthr->rs;
                    else
                        pfa->fa->rs = bthr->rs;
                }
                bthr->rs->fa = pfa->fa;
                if(_root == pfa) _root = bthr->rs;
                connect34(bthr->rs, bthr, pfa, bthr->ls, bthr->rs->ls, bthr->rs->rs, pfa->rs);
            }
            pfa->fa->RBc = oldRBc;
            return;
        }
        if(pfa->RBc) {                 BB-2R
            pfa->RBc = false;
            bthr->RBc = true;
            return;
        } else {                        BB-2B
            bthr->RBc = true;
            nn = pfa;
        }
    }
}

template <typename T>   先序遍历
void redblacktree<T>::previs(Node* ptn, int cnt) {
    if(ptn == NULL) return;
    printf("%d %s %d \n", ptn->val, ptn->RBc ? "Red" : "Black", ptn->s);
    if(!(ptn->RBc)) ++cnt;
    previs(ptn->ls, cnt);
    previs(ptn->rs, cnt);
}

template <typename T>   中序遍历
void redblacktree<T>::invis(Node* ptn, int cnt) {
    if(ptn == NULL) return;
    if(!(ptn->RBc)) ++cnt;
    invis(ptn->ls, cnt);
    printf("%d %s %d \n", ptn->val, ptn->RBc ? "Red" : "Black", ptn->s);
    invis(ptn->rs, cnt);
}

template <typename T>   后序遍历
void redblacktree<T>::postvis(Node* ptn, int cnt) {
    if(ptn == NULL) return;
    if(!(ptn->RBc)) ++cnt;
    postvis(ptn->ls, cnt);
    postvis(ptn->rs, cnt);
    printf("%d %s %d \n", ptn->val, ptn->RBc ? "Red" : "Black", ptn->s);
}

template <typename T>   输出所有序遍历的接口
void redblacktree<T>::vis() {
    printf("------pre-vis------\n");
    previs(_root, 0);
    printf("------in-vis------\n");
    invis(_root, 0);
    printf("------post-vis------\n");
    postvis(_root, 0);
}

template <typename T>   验证所有节点与父亲的连接是否正常、域s是否维护正常
void redblacktree<T>::checkconnect(Node* ptn) {
    if(!ptn) return;
    assert(ptn->s > 0);
    if(ptn->ls && ptn->ls->fa != ptn) {
        printf("Oops! %d has a ls %d, but it failed to point its fa!\n", ptn->val, ptn->ls->val);
    }
    if(ptn->rs && ptn->rs->fa != ptn) {
        printf("Oops! %d has a rs %d, but it failed to point its fa!\n", ptn->val, ptn->rs->val);
    }
    int sss = ptn->s;
    if(ptn->ls) sss -= ptn->ls->s;
    if(ptn->rs) sss -= ptn->rs->s;
    if(sss - 1) {
        printf("Damn! %d's size is %d, but the sum of its children's size is %d!\n", ptn->val, ptn->s, ptn->s - sss);
    }
    checkconnect(ptn->ls);
    checkconnect(ptn->rs);
}

template <typename T>
void redblacktree<T>::correctlyconnected() {
    checkconnect(_root);
}

const int maxn=1e5+10;
redblacktree<int > pre_tree,suf_tree;
int n,c,f,ans[maxn];
struct node{
    int score,aid;
    friend bool operator<(const node&a,const node&b){
        return a.score<b.score;
    }
}dat[maxn];

int main()
{
    scanf("%d %d %d",&n,&c,&f);
    for(int i=1;i<=c;i++){
        scanf("%d %d",&dat[i].score,&dat[i].aid);
    }
    sort(dat+1,dat+c+1);int sum=0;
    for(int i=1;i<=c;i++){
        if(pre_tree.size()==n/2){
            ans[i]+=sum;  
            pre_tree.insert(dat[i].aid);int maxx=*pre_tree.rbegin();
            pre_tree.erase(maxx);sum-=maxx;sum+=dat[i].aid;
        }else{
            pre_tree.insert(dat[i].aid);
            sum+=dat[i].aid;
        }
    }

    sum=0;
    for(int i=c;i>=1;i--){
        if(suf_tree.size()==n/2){
            ans[i]+=sum;          
            suf_tree.insert(dat[i].aid); int maxx=*suf_tree.rbegin();
            suf_tree.erase(maxx);sum-=maxx;sum+=dat[i].aid;

        }else{
            suf_tree.insert(dat[i].aid);
            sum+=dat[i].aid;
        }
    }  
    int res=-1;
    for(int i=n/2+1;i+n/2<=c;i++) if(ans[i]+dat[i].aid<=f) res=dat[i].score;
    printf("%d\n",res);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值