因为有删除,考虑倒序处理某个p的询问。
那么每天删除xi的蔬菜就变成了每天运来xi的蔬菜。那么我们取当前最优的即可,早取晚取都一样,不需要留给后面取,还能给后面更优的留出空间。 这样就只需考虑现在了。于是我们能得到p为某个值的答案。多次询问显然需要递推。 而p-1与p相比只是少卖了m的蔬菜。把收益最小的m个删掉即可。注意堆的插入删除顺序。
复杂度\(O(mqlogn)\)。还有一种求询问p的方法,是直接按蔬菜价值排序,然后每次找到其出现位置往前覆盖。如果某天已卖m则用并查集合并掉。
递推的时候sort一遍挨着删就可以。感觉离散化后线段树可做,第一次购买收益单独算一个,每个节点维护区间当前蔬菜种数、蔬菜总量、每天减少量。
正序做,每一天就选m个最大的,然后减掉这m个。 在某种蔬菜消失的那天直接Delete掉这种蔬菜(如果剩下1个下一天则Delete掉拆开的第一次购买收益)。 这样复杂度还与m无关。 不过...算了我就想想...写了写就弃了。//9424kb 1132ms#include#include #include #include #include //#define gc() getchar()#define MAXIN 400000#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)#define mp std::make_pair#define pr std::pair #define MAX 100000typedef long long LL;const int N=1e5+3;int A[N],S[N],tot[N],dec[N],use[N];LL Ans[N];std::vector v[N];std::queue tmp;std::priority_queue q1;std::priority_queue ,std::greater > q2;char IN[MAXIN],*SS=IN,*TT=IN;inline int read(){ int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now;}int main(){ int n=read(),m=read(),Q=read(); for(int i=1; i<=n; ++i) { A[i]=read(),S[i]=read(),tot[i]=read(),dec[i]=read(); if(!dec[i]) v[MAX].push_back(i);//上界! else v[std::min(MAX,(tot[i]+dec[i]-1)/dec[i])].push_back(i); } LL ans=0; for(int i=MAX; i; --i) { for(int j=0,k,l=v[i].size(); j