BZOJ2288:[POJ Challenge]生日礼物

浅谈堆:https://www.cnblogs.com/AKMer/p/10284629.html

题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=2288

首先我们可以把同符号的全部合成一个数,第一个如果是负数就扔了,最后一个也是。

然后把所有的正数都加起来,记段数为\(x\),若\(x<=m\)则这就是正确答案,否则我们需要使用一些手段让\(x\)降低为\(m\)。比如扔掉某些权值很小的正整数,或者加上某些绝对值很小的负数,这样都会使\(x--\)。但是如果我同时扔掉某个权值很小的正整数又加上这个数两边的负数显然是很蠢的,又或者我加上了某个绝对值很小的负数又扔掉这个负数两边的正数,显然也是很蠢的。

于是,我们往堆里扔所有数的绝对值,做一遍数据备份,不过每次是减去堆顶的值就行了。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

代码如下:

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

const int maxn=1e5+5;

int a[maxn];
int n,m,ans,cnt;

int read() {
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	return x*f;
}

struct Linked_List {
    int lst,nxt,val,in_heap;

    Linked_List() {}

    Linked_List(int _lst,int _nxt,int _val) {
        lst=_lst,nxt=_nxt,val=_val;
    }
}L[maxn];

struct Heap {
    int tot;
    int tree[maxn];

    bool less(int id1,int id2) {return L[id1].val<L[id2].val;}

    void up(int pos) {
        while(pos>1) {
            if(less(tree[pos],tree[pos>>1])) {
                swap(tree[pos],tree[pos>>1]);
                swap(L[tree[pos]].in_heap,L[tree[pos>>1]].in_heap);
                pos>>=1;
            }
            else break;
        }
    }

    void down(int pos) {
        int son=pos<<1;
        while(son<=tot) {
            if(son<tot&&less(tree[son|1],tree[son]))son|=1;
            if(less(tree[son],tree[pos])) {
                swap(tree[son],tree[pos]);
                swap(L[tree[son]].in_heap,L[tree[pos]].in_heap);
                pos=son,son=pos<<1;
            }
            else break;
        }
    }

    void ins(int v) {tree[++tot]=v,L[v].in_heap=tot,up(tot);}

    int pop() {
        int res=tree[1];
        tree[1]=tree[tot--];
        L[tree[1]].in_heap=1;
        down(1);return res;
    }

    void del(int id) {
        if(id==tot) {tot--;return;}
        tree[id]=tree[tot--];
        L[tree[id]].in_heap=id;
        if(id==1)down(id);
        else if(id==tot)up(id);
        else up(id),down(id);
    }
}T;

void work() {
	for(int i=1;i<=n;i+=2)
		ans+=a[i],m--;
	for(int i=1;i<=n;i++) {
		L[i]=Linked_List(i-1,i+1,abs(a[i]));
		T.ins(i);
    }
    while(m<0) {
        int id=T.pop(),lst=L[id].lst,nxt=L[id].nxt;ans-=L[id].val;
        if(!lst) {
            T.del(L[nxt].in_heap);m++;
            L[L[nxt].nxt].lst=0;continue;
        }
        if(nxt==n+1) {
            T.del(L[lst].in_heap);m++;
            L[L[lst].lst].nxt=n+1;continue;
        }
        T.del(L[lst].in_heap),T.del(L[nxt].in_heap);
        L[lst].val=L[lst].val+L[nxt].val-L[id].val;T.ins(lst);
        L[lst].nxt=L[nxt].nxt,L[L[nxt].nxt].lst=lst;m++;
    }
    printf("%d\n",ans);
}

int main() {
	n=read(),m=read();
	if(!m) {puts("0");return 0;}
	for(int i=1;i<=n;i++) {
		int x=read();
		if(!x)continue;
		if(!cnt&&x<0)continue;
		if(!cnt)a[++cnt]=x;
		else {
			if((a[cnt]<0)==(x<0))a[cnt]+=x;
			else a[++cnt]=x;
		}
	}
	if(a[cnt]<0)cnt--;
	n=cnt;work();
}
posted @ 2019-01-20 17:14  AKMer  阅读(173)  评论(0编辑  收藏  举报