2021湘潭邀请赛-热身赛-C-线段覆盖模型1

2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
在这里插入图片描述

题目大意:

给你 n n n个带有颜色的线段. m m m次询问,每次询问一个区间完全包含多少个不同颜色的线段.

题目思路:
离线:

类似HH的项链,但是变成区间问题了.

处理区间问题,利用扫描线的思想:我们可以对线段&区间按左端点排序。然后从后往前扫描,
遇到线段的左端点,则将对应右端点的位置的值+1.然后将该颜色上次出现的位置的值-1,取消贡献。
遇到查询时,直接树状数组查区间和.

原因显然:从后往前的过程中,对于一种颜色,我们只关心它当前最左边的出现(该位置最有可能有贡献).所以我们可以把该贡献记录在当前出现最左边的位置.

强制在线:主席树

若该问题强制在线了,那么我们就直接上主席树记录下每一个后缀树即可。由于这题涉及到离散化。那么就对左端点,二分大于等于L的位置.右端点二分最后一个小于等于R的位置即可.

主席树解法参考代码(已小范围暴力对拍):

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
#define mid ((l + r) >> 1)
const int maxn = 4e5 + 5;
const int mod = 1e9 + 7;
int n , m;
struct Node{
    int l , r , c;
    bool operator < (const Node & a){
        return l > a.l;
    }
}q[maxn] , b[maxn];
vector<Node> a[maxn];
int dist[maxn] , tot;
int rt[maxn] , s[maxn << 4] , ls[maxn << 4] , rs[maxn << 4] , cnt;
void pushup (int t)
{
    int tl = ls[t] , tr = rs[t];
    s[t] = s[tl] + s[tr];
}
int add (int t , int l , int r , int p , int c)
{
    int now = ++cnt;
    ls[now] = ls[t];
    rs[now] = rs[t];
    if (l == r){
        s[now] = s[t] + c;
        return now;
    }
    if (p <= mid) ls[now] = add(ls[now] , l , mid , p , c);
    else rs[now] = add(rs[now] , mid + 1 , r , p , c);
    pushup(now);
    return now;
}
int ask (int t , int l , int r , int L , int R)
{
    if (L <= l && r <= R) return s[t];
    int ans = 0;
    if (L <= mid) ans += ask(ls[t] , l , mid , L , R);
    if (R > mid) ans += ask(rs[t] , mid + 1 , r , L , R);
    return ans;
}
int last[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1 ; i <= n ; i++){
        cin >> b[i].c >> b[i].l >> b[i].r;
        dist[++tot] = b[i].l;
        dist[++tot] = b[i].r;
    }
    for (int i = 1 ; i <= m ; i++){
        cin >> q[i].l >> q[i].r;
        dist[++tot] = q[i].l;
        dist[++tot] = q[i].r;
    }
    // ÀëÉ¢»¯
    sort(dist + 1 , dist + 1 + tot);
    tot = unique(dist + 1 , dist + 1 + tot) - dist - 1;
    for (int i = 1 ; i <= n ; i++){
        b[i].l = lower_bound(dist + 1 , dist + 1 + tot , b[i].l) - dist;
        b[i].r = lower_bound(dist + 1 , dist + 1 + tot , b[i].r) - dist;
        a[b[i].l].push_back(b[i]);
    }
    for (int i = 1 ; i <= m ; i++){
        q[i].l = lower_bound(dist + 1 , dist + 1 + tot , q[i].l) - dist;
        q[i].r = lower_bound(dist + 1 , dist + 1 + tot , q[i].r) - dist;
    }
    //
    sort(b + 1 , b + 1 + n);
    memset(last , -1 , sizeof last);
    for (int i = tot ; i >= 1 ; i--){
        rt[i] = rt[i + 1];
        for (auto g : a[i]){
            if (last[g.c] == -1 || last[g.c] > g.r){
                rt[i] = add(rt[i] , 1 , tot , g.r , 1);
                if (last[g.c] != -1)
                    rt[i] = add(rt[i] , 1 , tot , last[g.c] , -1);
                last[g.c] = g.r;
            }
        }
    }
    for (int i = 1 ; i <= m ; i++){
        cout << ask(rt[q[i].l] , 1 , tot , q[i].l , q[i].r) << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值