1. 程式人生 > >bzoj 2288: 【POJ Challenge】生日禮物【鏈表+堆】

bzoj 2288: 【POJ Challenge】生日禮物【鏈表+堆】

logs 絕對值 pri article turn .net clu tails zoj

參考:http://blog.csdn.net/w_yqts/article/details/76037315
把相同符號的連續數字加起來,合並後ans先貪心的加上所有正數,如果正數個數sum>m,設計二元組(i,a[i])表示合並後序列i位置上值為a,記錄前驅後繼,塞進按絕對值排序的小根堆裏。每次拿出來一個,減去這個x的a的絕對值,然後合並左右前驅後繼,再塞回去。
如果拿出來的是正數,那麽減去相當於原來選了現在不選,如果是負數,減去相當於選。
然後a值要改成a[l]+a[r]+a[x],下次再選這個區間的話,相當於對x進行逆操作。
註意邊界,邊界上的負數沒用。

#include<iostream>
#include<cstdio> #include<queue> #include<algorithm> using namespace std; const int N=100005,inf=1e9;; int n,m,a[N],tot=1,ne[N],pr[N],ans,sum; bool v[N]; // priority_queue<pair<int,int> >q; struct cmp { bool operator()(pair<int,int> a,pair<int,int> b) { return
abs(a.first)>abs(b.first); } }; priority_queue<pair<int,int>,vector<pair<int,int> >,cmp>q; int read() { int r=0,f=1; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘
) { r=r*10+p-48; p=getchar(); } return r*f; } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) { int x=read(); if((long long)a[tot]*x>=0) a[tot]+=x; else a[++tot]=x; } for(int i=1;i<=tot;i++) {//cout<<a[i]<<endl; if(a[i]>0) ans+=a[i],sum++; pr[i]=i-1; ne[i]=i+1; q.push(make_pair(a[i],i)); } pr[1]=0,ne[tot]=0; while(sum>m) { sum--; while(v[q.top().second]) q.pop(); int x=q.top().second,l=pr[x],r=ne[x]; q.pop(); if(l&&r) ans-=abs(a[x]); else if(a[x]>0) ans-=a[x]; else { sum++;//邊界上的負數不能取,要把減去的sum加回來 continue; } a[x]=a[l]+a[r]+a[x]; v[l]=1;v[r]=1; pr[ne[l]]=pr[l],pr[ne[r]]=pr[r]; ne[pr[l]]=ne[l],ne[pr[r]]=ne[r]; q.push(make_pair(a[x],x)); } printf("%d\n",ans); return 0; }

bzoj 2288: 【POJ Challenge】生日禮物【鏈表+堆】