题意
好长懒得写。
分析
先考虑如果只有一组询问的话要怎么做。
不难想到我们可以反过来贪心,这样删物品就变成了加物品,只要用一个堆来维护下就好了。
现在有多组询问的话,先找到最大的询问mx,然后做一次贪心得到第mx天的答案。
因为若某件物品在第t天一定能买,则其在第t天之前也一定能买。那么如果我们知道第t天的答案,可以通过把第t天的物品贪心地填进前t-1天来得到第t-1天的答案。
那么只要用并查集维护一下哪些时间还没被填完,如果有的话就直接填进去,否则就在前面的所有蔬菜里面替换掉价值最小的。
实现起来细节比较多。
时间复杂度
O(nmlogn)
O
(
n
m
l
o
g
n
)
。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define mp(x,y) std::make_pair(x,y)
typedef long long LL;
typedef std::pair<int,int> pi;
const int N=100005;
int n,m,k,val[N],s[N],c[N],x[N],q[N],a[N],f[N],ob[N],da[N];
LL ans[N];
std::priority_queue<pi> que;
std::vector<int> beg[N];
struct Queue
{
std::priority_queue<pi> a,b;
void work() {while (!b.empty()&&a.top()==b.top()) a.pop(),b.pop();}
void push(pi x) {a.push(x);}
void erase(pi x) {b.push(x);}
pi top() {work();return a.top();}
bool empty() {work();return a.empty();}
void pop() {work();a.pop();}
}Q,tmp[N];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int find(int x)
{
if (f[x]==x) return x;
else return f[x]=find(f[x]);
}
int get_sum(int id,int y)
{
if (!x[id]) return 0;
else return x[id]*y;
}
int main()
{
n=read();m=read();k=read();
for (int i=1;i<=n;i++) val[i]=read(),s[i]=read(),c[i]=read(),x[i]=read();
int mx=0;
for (int i=1;i<=k;i++) q[i]=read(),mx=std::max(mx,q[i]);
for (int i=0;i<=mx;i++) f[i]=i;
for (int i=1;i<=n;i++)
if (!x[i]) beg[mx].push_back(i);
else beg[std::min((c[i]-1)/x[i]+1,mx)].push_back(i);
for (int i=mx;i>=1;i--)
{
for (int j=0;j<beg[i].size();j++)
{
int id=beg[i][j];
if (!ob[id]) que.push(mp(val[id]+s[id],id));
else que.push(mp(val[id],id));
}
while (da[i]<m)
{
if (que.empty()) break;
int u=que.top().first,id=que.top().second;que.pop();
ans[mx]+=u;tmp[i].push(mp(u,i));Q.push(mp(-u,i));da[i]++;ob[id]++;
if (c[id]-get_sum(id,i-1)-ob[id]>0) que.push(mp(val[id],id));
else if (get_sum(id,i-1)>0) beg[i-1].push_back(id);
}
if (da[i]==m) f[i]=i-1;
}
for (int i=mx;i>1;i--)
{
ans[i-1]=ans[i];
int tot=0;
while (!tmp[i].empty()) a[++tot]=tmp[i].top().first,tmp[i].pop(),Q.erase(mp(-a[tot],i));
std::reverse(a+1,a+tot+1);
while (find(i-1)>0&&tot)
{
int id=find(i-1);
tmp[id].push(mp(a[tot],id));
Q.push(mp(-a[tot],id));
tot--;da[id]++;
if (da[id]==m) f[id]=id-1;
}
while (!Q.empty()&&tot&&-Q.top().first<a[tot])
{
int u=Q.top().first,id=Q.top().second;
ans[i-1]+=u;Q.pop();
tmp[id].erase(mp(-u,id));tmp[id].push(mp(a[tot],id));
Q.push(mp(-a[tot],id));tot--;
}
while (tot) ans[i-1]-=a[tot],tot--;
}
for (int i=1;i<=k;i++) printf("%lld\n",ans[q[i]]);
return 0;
}