洛谷新春OI集训营 - 省选 Day1 T3 过年

这篇博客介绍了洛谷新春OI集训营的省选Day1第三题,涉及一个关于区间礼物分发的问题。题目要求在限定范围内发放礼物,并对每个小朋友接收到的礼物中出现次数最多者进行统计。算法解决方案采用了扫描线、差分和线段树技术,通过将操作差分并用线段树维护区间最大值和编号,最终实现求解每个小朋友接收到的最常见礼物。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: https://www.luogu.org/problemnew/show/T21778

有 n(1n≤ 1e5) 个小朋友,过年了,要发放 m(1m≤ 1e5) 次礼物。

每次发放,会给出三个参数 l,r,k(1lrn,1k≤ 1e5) ,表示给区间 [l,r] 内的小朋友都发一个礼物 k 。

所有礼物发放完成后,对于每一个小朋友,回答他接受的礼物中,出现次数最多的礼物是什么。如果有多个,输出编号最小的那个;如果不存在,输出 -1 。

算法:扫描线、差分、线段树

将每一个l~r发礼物的操作差分为位置l数量+1,位置r+1数量-1

线段树维护一段礼物的最大数量和编号

从1至n循环,每次将这个位置的操作加入线段树后根节点的数据即为答案

代码如下:

#include<bits/stdc++.h>
#define sz 100010
using namespace std;
int n,m;
vector<int>vec[sz];//vec[i]存储第i个小朋友的差分操作
pair<int,int> a[10001010];//a存储线段树,first:子树中礼物最大数量 second:子树中数量最多的礼物中最小的编号
void build(int rt,int l,int r)//建树
{
    a[rt].second=l;
    if (l<r)
    {
        int mid=(l+r)>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
    }
}
void push_up(int rt)//更新rt节点
{
    a[rt].first=max(a[rt<<1].first,a[rt<<1|1].first);
    if (a[rt<<1].first>=a[rt<<1|1].first) a[rt].second=a[rt<<1].second;
    else a[rt].second=a[rt<<1|1].second;
}
void add(int rt,int l,int r,int pos,int k)//第pos个礼物数量+=k
{
    if (l==r) {a[rt].first+=k;return;}
    int mid=(l+r)>>1;
    if (pos<=mid) add(rt<<1,l,mid,pos,k);
    else add(rt<<1|1,mid+1,r,pos,k);
    push_up(rt);
}
int main()
{
    scanf("%d %d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int l,r,x;
        scanf("%d %d %d",&l,&r,&x);
        vec[l].push_back(x);
        vec[r+1].push_back(-x);
        //差分 正数表示+1,负数表示-1
    }
    build(1,1,sz);
    for (int i=1;i<=n;i++)
    {
        for (int j=0;j<vec[i].size();j++)
        {
            int cur=vec[i][j];
            if (cur>0) add(1,1,sz,cur,1);
            else add(1,1,sz,-cur,-1);
        }
        pair<int,int>ans=a[1];//a[1]是根节点 
        if (ans.first==0) ans.second=-1;//如果没有礼物输出-1 
        printf("%d\n",ans.second);
    }
}

个人认为这是Day1三道题中最简单的题了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值