C110 整体二分+线段树 P4602 [CTSC2018] 混合果汁
视频链接:C110 整体二分+线段树 P4602 [CTSC2018] 混合果汁_哔哩哔哩_bilibili
// 整体二分+线段树 O(n*logn*logn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define ls (u<<1) #define rs (u<<1|1) typedef long long LL; const int N=100005; int n,m,X,ans[N]; struct A{ //果汁美味度d,每升价格p,添加体积上限v int d,p,v; bool operator<(A b){return d>b.d;} }a[N]; struct Q{ //小朋友最多支付g,至少要L升,编号id LL g,L; int id; }q[N],q1[N],q2[N]; struct Segtree{ //线段树的权值为价格 LL vol[N<<2],pri[N<<2]; //总体积,总价格 void pushup(int u){ //上传 vol[u]=vol[ls]+vol[rs]; pri[u]=pri[ls]+pri[rs]; } void change(int p,int v,int u=1,int l=1,int r=N){ //点修 if(l==r){vol[u]+=v;pri[u]=l*vol[u];return;} int mid=l+r>>1; if(p<=mid)change(p,v,ls,l,mid); else change(p,v,rs,mid+1,r); pushup(u); } LL query(LL v,int u=1,int l=1,int r=N){ //点查 if(!v)return 0; if(l==r)return l*v; //返回价格零头 int mid=l+r>>1; if(vol[ls]>=v)return query(v,ls,l,mid); return pri[ls]+query(v-vol[ls],rs,mid+1,r); } }T; void solve(int l,int r,int L,int R){ if(l>r)return; if(L==R){ //记录分流到第L种果汁的小朋友 for(int i=l;i<=r;i++)ans[q[i].id]=a[L].d; return; } int mid=L+R>>1,p1=0,p2=0; //二分果汁mid //线段树维护mid左边的果汁的总体积和总价格 while(X<mid) ++X,T.change(a[X].p,a[X].v); while(X>mid) T.change(a[X].p,-a[X].v),--X; for(int i=l;i<=r;i++){ //第i个小朋友的需求能满足,则分流到左边 if(T.vol[1]>=q[i].L&&T.query(q[i].L)<=q[i].g) q1[++p1]=q[i]; else q2[++p2]=q[i]; //否则,分流到右边 } for(int i=1;i<=p1;i++)q[l+i-1]=q1[i]; for(int i=1;i<=p2;i++)q[l+p1+i-1]=q2[i]; solve(l,l+p1-1,L,mid); solve(l+p1,r,mid+1,R); //分治 } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) //n种果汁 scanf("%d%d%d",&a[i].d,&a[i].p,&a[i].v); a[++n]={-1,0,0}; //无解的归宿 sort(a+1,a+1+n); //按美味度降序 for(int i=1;i<=m;i++) //m个小朋友 scanf("%lld%lld",&q[i].g,&q[i].L),q[i].id=i; solve(1,m,1,n); //分流小朋友,二分果汁 for(int i=1;i<=m;i++)printf("%d\n",ans[i]); }
// 整体二分+树状数组 O(n*logn*logn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define N 100005 #define lowbit(x) (x&-x) typedef long long LL; LL n,m,X,ans[N]; struct A{ LL d,p,v; bool operator<(A b){return d>b.d;} }a[N]; struct Q{ LL g,L;int id; }q[N],q1[N],q2[N]; struct BIT{ LL s[N]; void add(int x,LL v){ while(x<=N)s[x]+=v,x+=lowbit(x); } LL sum(int x){ LL t=0; while(x)t+=s[x],x-=lowbit(x); return t; } }vol,pri; void change(int x,int k){ vol.add(a[x].p,k*a[x].v), pri.add(a[x].p,k*a[x].p*a[x].v); } LL find(int x){ int l=0,r=N+1; while(l+1<r){ int mid=(l+r)>>1; if(vol.sum(mid)>=q[x].L) r=mid; else l=mid; } return r; } void solve(int l,int r,int L,int R){ if(l>r) return; if(L==R){ for(int i=l;i<=r;++i)ans[q[i].id]=a[L].d; return; } int mid=(L+R)>>1,p1=0,p2=0; while(X<mid) change(++X,1); while(X>mid) change(X--,-1); for(int i=l;i<=r;++i){ LL x=find(i),v=vol.sum(x),p=pri.sum(x); if(v>=q[i].L&&p-x*(v-q[i].L)<=q[i].g) q1[++p1]=q[i]; else q2[++p2]=q[i]; } for(int i=1;i<=p1;++i) q[l+i-1]=q1[i]; for(int i=1;i<=p2;++i) q[l+p1+i-1]=q2[i]; solve(l,l+p1-1,L,mid); solve(l+p1,r,mid+1,R); } int main(){ scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) //n种果汁 scanf("%lld%lld%lld",&a[i].d,&a[i].p,&a[i].v); a[++n]={-1,0,0}; //无解的归宿 sort(a+1,a+1+n); //按美味度降序 for(int i=1;i<=m;i++) //m个小朋友 scanf("%lld%lld",&q[i].g,&q[i].L),q[i].id=i; solve(1,m,1,n); //分流小朋友,二分果汁 for(int i=1;i<=m;i++)printf("%lld\n",ans[i]); }
分类:
C 数据结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!