2022.8.4 JC题解

本文介绍了如何运用线段树解决一道区间修改与查询的编程题目,强调了奶牛上车问题的处理细节,包括区间最小值的查询与更新操作,以及如何避免超时。通过案例解析了线段树在动态维护区间信息中的应用,并给出了完整的C++代码实现。

T2 诺亚方舟

吐槽:题目的坑好离谱……

本题是线段树区间修改,区间查询的题目

题目中说优先搭载买票先的奶牛,所以一头奶牛上不了车可以直接放弃,无需考虑次序问题。

每一头奶牛上车以后都会增加 111 个当前载客量,所以我们用 ansians_{i}ansi
表示列车到达第 iii 个站点的剩余载客量,初始值都为 kkk ,一旦奶牛所经过的某个站点满载(ansians_{i}ansi 等于 000 )当前奶牛就无法上车。

每次给定奶牛的起点和终点,如果使用朴素做法从起点到终点枚举将奶牛经过的站点剩余载客量 −1-11 就会超时(50pts\text{50pts}50pts ),所以我们考虑用线段树维护区间内剩余载客量最小值并做每一次的修改。

每次读入 aaabbbquery\text{query}query 一次,将 ansaans_{a}ansa ~ ansb−1ans_{b-1}ansb1 (坑点:奶牛下车以后不会占用载客量,所以终点的剩余载客量不用减)

若最小值小于等于 000 ,则当前奶牛不能上车,直接放弃
若最小值大于 000 ,则当前奶牛上车,并将 ansaans_{a}ansa ~ ansb−1ans_{b-1}ansb1 中的每个数加 111update\text{update}update 函数),表示该站点的载客量 +1+1+1
最后注意输出格式等就能 $\text{AC} $ 了。

Tips\text{Tips}Tips : 由于行末不能有空格,可以将答案储存到一个答案数组后输出。


Coding Time\text{Coding Time}Coding Time


#include<bits/stdc++.h>
using namespace std;
int sum[4000005],ans[4000005],n,T,m,x[1000005],y[1000005],s[1000005],xb;
void push_down(int p)
{
    if(sum[p])
    {
        ans[p<<1]+=sum[p];
        ans[p<<1|1]+=sum[p];
        sum[p<<1]+=sum[p];
        sum[p<<1|1]+=sum[p];
        sum[p]=0;
    }
}
void update(int p,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr)
    {
        ans[p]--;//将当前剩余载客量-1
        sum[p]--;//懒人标记也要-1
        return;
    }
    push_down(p);//标记下传
    int mid=l+r>>1;
    if(ql<=mid)
      update(p<<1,l,mid,ql,qr);
    if(mid<qr)
      update(p<<1|1,mid+1,r,ql,qr);
    ans[p]=min(ans[p<<1],ans[p<<1|1]);
}
int query(int p,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr)
      return ans[p];
    push_down(p);
    int mid=l+r>>1;
    int mn=2e9;
    if(ql<=mid)
      mn=min(mn,query(p<<1,l,mid,ql,qr));
    if(qr>mid)
      mn=min(mn,query(p<<1|1,mid+1,r,ql,qr));
    return mn;
}
int main()
{
    cin>>T;
    for(int whxakioi=1;whxakioi<=T;++whxakioi)
    {
        xb=0;//清空答案数组
        cout<<"Case "<<whxakioi<<":\n";
        cin>>n>>m;
        int mx=0;
        for(int i=1;i<=m;++i)
        {
            cin>>x[i]>>y[i];
            --y[i];//一开始就将终点-1,如上所述
            mx=max(mx,y[i]);//求出下车点最大值
        }
        for(int i=1;i<=mx*4;++i)//初值
          ans[i]=n,sum[i]=0;
        for(int i=1;i<=m;++i)
        {
            if(query(1,1,mx,x[i],y[i])>0)//若区间最小值大于0,则奶牛可以上车
            {
                s[++xb]=i;//记录到答案数组中
                update(1,1,mx,x[i],y[i]);//区间修改
            }
        }
        if(xb==0)
          cout<<"\n\n";//输出两个换行
        for(int i=1;i<=xb;++i)
          if(i==xb)
            cout<<s[i]<<"\n\n";else
            cout<<s[i]<<' ';
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值