CF #569 Div. 2 E:Serge and Dining Room//区间最小线段树

题意:n个dish,每个有一个价格ai,m个pupil排成一队,每个pupil有bi的钱,每个pupil都尽量买自己买的起的最贵的dish,求等m个pupil都买完后,能够买到最贵的dish是多少价格x。

有q个询问,每次可以改变一个ai或者bi,然后求上述的x。

思路:将ai和bi维护进桶,然后用线段树维护。

线段树每一个区间节点维护的是(bi-ai)的后缀和。

那么(bi-ai)的后缀和 从后到前的第一个小于0的位置就是可以买的最贵的x。

修改也很方便,只需要将一段前缀和修改+1。

总结:

线段树有时候并不需要build出一个树形。

线段树可以直接查询[1,n]最小值的下标,左右递归即可;而如果要求某一段[l,r]的最小值下标,就比较麻烦。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
const LL mod =1e9+7;
const int MX = 1e6+5;
int n,m;int a[MX],b[MX],ina[MX],inb[MX];//dish,pupil
int lazy[MX<<2],tree[MX<<2];

inline void pushUp(int root){
    tree[root]=min(tree[root<<1],tree[root<<1|1]);
}

void pushDown(int root){
    if(lazy[root]){
        lazy[root<<1]+=lazy[root];
        lazy[root<<1|1]+=lazy[root];
        tree[root<<1]+=lazy[root];
        tree[root<<1|1]+=lazy[root];
        lazy[root]=0;
    }
}
void update(int L,int R,int c,int l,int r,int root){
    if(l>=L&&r<=R){
        lazy[root]+=c;
        tree[root]+=c;
        return;
    }
    pushDown(root);
    int m=(l+r)>>1;
    if(m>=L) update(L,R,c,l,m,root<<1);
    if(m<R)  update(L,R,c,m+1,r,root<<1|1);
    pushUp(root);
}
int query(int l,int r,int root){
    if(l==r)
        return tree[root]<0?l:-1;
    pushDown(root);
    int m=(l+r)>>1;
    if(tree[root<<1|1]<0){return query(m+1,r,root<<1|1); }
    return query(l,m,root<<1);
}


int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){scanf("%d",&ina[i]);a[ina[i]]++;}
    for(int i=1;i<=m;i++){scanf("%d",&inb[i]);b[inb[i]]++;}
    for(int i=1;i<=1e6;i++)
        update(1,i,b[i]-a[i],1,1e6,1);
    int q;cin>>q;
    while(q--){
        int op,p,val;scanf("%d%d%d",&op,&p,&val);
        if(op==1){
            update(1,val,-1,1,1e6,1);
            update(1,ina[p],1,1,1e6,1);
            ina[p]=val;
        }
        else {
            update(1,val,1,1,1e6,1);
            update(1,inb[p],-1,1,1e6,1);
            inb[p]=val;
        }
        printf("%d\n",query(1,1e6,1));
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值