每次询问去掉物品i之后,j的钱最多可以买多大价值的东西。
我们可以分治[l,r]表示l~r的物品不买的背包数组。然后递归处理[l,mid]时把[mid+1,r]的物品转移进来,递归处理[mid+1,r]时把[l,mid]的物品转移进来。
转移的时候就是一个多重背包,可以单调队列优化。
复杂度
O(nmlogn)
O
(
n
m
l
o
g
n
)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 1010
#define pa pair<int,int>
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int ans[N][N],n,m=1000,a[N],b[N],c[N],f[11][N];
pa q[N];
inline void Max(int &x,int y){if(x<y) x=y;}
inline void work(int *f,int l,int r){
for(int i=l;i<=r;++i)
for(int j=0;j<a[i];++j){
int qh=1,qt=0;
for(int k=0;;++k){
int x=k*a[i]+j;if(x>m) break;
while(qh<=qt&&k-q[qh].second>c[i]) ++qh;
while(qh<=qt&&f[x]-k*b[i]>=q[qt].first) --qt;
q[++qt]=make_pair(f[x]-k*b[i],k);
Max(f[x],q[qh].first+k*b[i]);
}
}
}
inline void solve(int l,int r,int lev){//l~r is unavailable
if(l==r){memcpy(ans[l],f[lev],sizeof(f[lev]));return;}
int mid=l+r>>1;
memcpy(f[lev+1],f[lev],sizeof(f[lev]));
work(f[lev+1],mid+1,r);solve(l,mid,lev+1);
memcpy(f[lev+1],f[lev],sizeof(f[lev]));
work(f[lev+1],l,mid);solve(mid+1,r,lev+1);
}
int main(){
// freopen("a.in","r",stdin);
n=read();
for(int i=1;i<=n;++i) a[i]=read(),b[i]=read(),c[i]=read();
solve(1,n,0);m=read();
while(m--){
int x=read()+1,y=read();
printf("%d\n",ans[x][y]);
}return 0;
}