链接:http://codeforces.com/contest/1106/problem/B
题意:一家饭店有n个菜,每个菜有两个属性:数量和价格。 有m个人按顺序去点菜,每个人有两个值t和d表示想要的菜的编号和数量。
1.当一个人想要的菜还有时,会优先点。
2.当想要的菜没有时,优先点最便宜且下标最小的菜
3.当所有菜都不足时,这个人的答案就是0
思路:用一个线段树维护一下所有菜中最便宜且下标最小的就可以了。(一开始想用堆维护,但是操作中需要直接对菜的数量进行更新)
#include<bits/stdc++.h>
using namespace std;
typedef __int64 ll;
const ll maxn=1e5+5;
ll a[maxn],c[maxn];
ll tree[maxn<<2];
#define lson rt<<1
#define rson rt<<1|1
ll cnt=0;
void bulid(ll rt,ll l,ll r)
{
if(l==r)
{
tree[rt]=++cnt;
return;
}
ll mid=(l+r)>>1;
bulid(lson,l,mid);
bulid(rson,mid+1,r);
if(c[tree[lson]]<=c[tree[rson]])tree[rt]=tree[lson];
else tree[rt]=tree[rson];
}
void updata(ll rt,ll l,ll r,ll id,ll val)
{
if(l==r&&l==id)
{
a[tree[rt]]-=val;
if(a[tree[rt]]==0)tree[rt]=-1;//-1表示这个菜没有了
return;
}
ll mid=(l+r)>>1;
if(id<=mid)updata(lson,l,mid,id,val);
else updata(rson,mid+1,r,id,val);
if(tree[lson]==-1&&tree[rson]==-1)tree[rt]=-1;
else if(tree[lson]==-1)tree[rt]=tree[rson];
else if(tree[rson]==-1)tree[rt]=tree[lson];
else if(c[tree[lson]]<=c[tree[rson]])tree[rt]=tree[lson];
else tree[rt]=tree[rson];
}
int main()
{
ll n,m;
scanf("%I64d%I64d",&n, &m);
for(ll i=1;i<=n;i++)
scanf("%I64d",&a[i]);
for(ll i=1;i<=n;i++)
scanf("%I64d",&c[i]);
bulid(1,1,n);
ll x,y;
for(ll i=1;i<=m;i++)
{
scanf("%I64d%I64d",&x,&y);
if(a[x]>y)
{
a[x]-=y;
printf("%I64d\n",c[x]*y);
}
else if(a[x]==y)
{
a[x]-=y;
updata(1,1,n,x,0);
printf("%I64d\n",c[x]*y);
}
else
{
ll ans=0;
if(a[x]!=0)
{
ans+=c[x]*a[x];
y-=a[x];
updata(1,1,n,x,a[x]);
}
bool ff=false;
while(y)
{
ll now=tree[1];
if(now==-1)
{
ff=true;
break;
}
if(a[now]>y)
{
a[now]-=y;
ans+=c[now]*y;
y=0;
}
else if(a[now]==y)
{
updata(1,1,n,now,y);
ans+=c[now]*y;
y=0;
}
else
{
ans+=c[now]*a[now];
y-=a[now];
updata(1,1,n,now,a[now]);
}
}
if(ff)ans=0;
printf("%I64d\n",ans);
}
// for(ll i=1;i<=n;i++)
// prllf("%d%c",a[i],i==n?'\n':' ');
}
return 0;
}