CF500F New Year Shopping
Link
Description
有 \(n\) 个物品,每个物品有价值 \(v\)、体积 \(w\) 和时间区间 \([l,r]\)。\(q\) 次询问,每次问在 \(a\) 时刻花至多 \(b\) 元能买到的最大价值和。
Solution
按时间将询问离线,然后按时间建线段树,把物品的影响加到 vector ,dfs 线段树,合并背包即可。
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
#define M 20007
#define N 4000
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
struct Que{int t,b,pos;}x[M];
struct Node{int l,r,v,w;}a[N+1];
int n,p,X[M],ans[M],top=0,sta[20][N+1];
vector<Que> Q[M];
inline int max(int x,int y){return x>y? x:y;}
void dfs(const vector<Node> &V,int lf,int rf){
++top;
for(int i=0;i<=N;i++)
sta[top][i]=sta[top-1][i];
vector<Node> L,R;
for(int i=0;i<V.size();i++)
if(V[i].l<=lf&&rf<=V[i].r){
for(int j=N;j>=V[i].w;j--)
sta[top][j]=max(sta[top][j],sta[top][j-V[i].w]+V[i].v);
}else if(lf!=rf){
int mid=(lf+rf)>>1;
if(V[i].l<=mid) L.push_back(V[i]);
if(V[i].r>mid) R.push_back(V[i]);
}
if(lf==rf){
for(int i=0;i<Q[lf].size();i++)
ans[Q[lf][i].pos]=sta[top][Q[lf][i].b];
}else{
int mid=(lf+rf)>>1;
dfs(L,lf,mid),dfs(R,mid+1,rf);
}
top--;
}
int main(){
n=read(),p=read();
vector<Node> V;
for(int i=1,r;i<=n;i++){
int w=read(),v=read(),l=read();
a[i]=(Node){l,l+p-1,v,w};
}
int q=read();
for(int i=1;i<=q;i++){
x[i].t=read(),x[i].b=read();
X[i]=x[i].t,x[i].pos=i;
}
sort(X+1,X+1+q);
int sz=unique(X+1,X+1+q)-(X+1);
for(int i=1;i<=q;i++){
int t=lower_bound(X+1,X+1+sz,x[i].t)-X;
Q[t].push_back(x[i]);
}
for(int i=1;i<=n;i++){
a[i].l=lower_bound(X+1,X+1+sz,a[i].l)-X;
a[i].r=upper_bound(X+1,X+1+sz,a[i].r)-X-1;
V.push_back(a[i]);
}
dfs(V,1,sz);
for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
}