bzoj 2288: 【POJ Challenge】生日禮物【鏈表+堆】
阿新 • • 發佈:2018-02-08
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】生日禮物【鏈表+堆】