C110 整体二分+线段树 P4602 [CTSC2018] 混合果汁

视频链接:C110 整体二分+线段树 P4602 [CTSC2018] 混合果汁_哔哩哔哩_bilibili

 

 

 

Luogu P4602 [CTSC2018] 混合果汁

复制代码
// 整体二分+线段树 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]);
}
复制代码

 

posted @   董晓  阅读(148)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示