严格按题解写,看能不能形成sum,只需要分割当前sum怎么由两边组成就好
#include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> using namespace std; const int INF = 0x3f3f3f3f; const int N = 2e4+100; int f[N][105],g[N][105]; int ret[N*5],v[N],d[N],T,n,m; struct Que { int l,r,c,sum,id; } p[N*5]; void cdq(int l,int r,int x,int y) { int mid=(l+r)>>1; vector<Que>lf,rt,cur; lf.clear(),rt.clear(),cur.clear(); for(int i=x; i<=y; ++i) { if(p[i].l>mid)rt.push_back(p[i]); else if(p[i].r<mid)lf.push_back(p[i]); else cur.push_back(p[i]); } if(cur.size()) { for(int i=0; i<=100; ++i)f[mid][i]=g[mid][i]=INF; f[mid][v[mid]]=d[mid]; for(int i=mid-1; i>=l; --i) { for(int j=0; j<=100; ++j) { if(j>=v[i]) { if(j-v[i]==0)f[i][j]=min(f[i+1][j],d[i]); else f[i][j]=min(f[i+1][j],max(f[i+1][j-v[i]],d[i])); } else f[i][j]=f[i+1][j]; } } for(int i=mid+1; i<=r; ++i) { for(int j=0; j<=100; ++j) { if(j>=v[i]) { if(j-v[i]==0)g[i][j]=min(g[i-1][j],d[i]); else g[i][j]=min(g[i-1][j],max(g[i-1][j-v[i]],d[i])); } else g[i][j]=g[i-1][j]; } } for(int i=0; i<cur.size(); ++i) { if(cur[i].r==mid) { if(f[cur[i].l][cur[i].sum]>cur[i].c)ret[cur[i].id]=1; continue; } bool flag=false; for(int j=0; j<=cur[i].sum; ++j) { int dis; if(!j)dis=g[cur[i].r][cur[i].sum-j]; else if(j==cur[i].sum)dis=f[cur[i].l][j]; else dis=max(f[cur[i].l][j],g[cur[i].r][cur[i].sum-j]); if(dis<=cur[i].c) { flag=true; break; } } if(!flag)ret[cur[i].id]=1; } } int cnt=x-1; if(lf.size()) { for(int i=0; i<lf.size(); ++i) p[++cnt]=lf[i]; cdq(l,mid,x,cnt); } if(rt.size()) { x=cnt+1; for(int i=0; i<rt.size(); ++i) p[++cnt]=rt[i]; cdq(mid+1,r,x,cnt); } } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1; i<=n; ++i)scanf("%d",&v[i]); for(int i=1; i<=n; ++i)scanf("%d",&d[i]); for(int i=1; i<=m; ++i) { scanf("%d%d%d%d",&p[i].l,&p[i].r,&p[i].c,&p[i].sum); p[i].id=i; ret[i]=0; } cdq(1,n,1,m); for(int i=1; i<=m; ++i)printf("%d",ret[i]); printf(" "); } return 0; }