n组区间,每组选一个区间,使得所选区间的交集不为空集的方案数

题目

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5e5 + 5, mod = 1e9 + 7;
int cnt[maxn];//cnt[i]表示第i组区间覆盖当前点多少次
int mp[3];//mp[i]表示覆盖当前点i次的,有多少组区间
int pw[maxn];//2的幂次
struct Seg{
    int pos, mark, id;
    bool operator<(const Seg &x)const{
        if(pos != x.pos) 
            return pos < x.pos;
        return mark < x.mark;//pos相同时,必须先遍历以pos为结尾的区间
    }
}seg[maxn * 4];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n, i, j;
    cin >> n;
    int l, r;
    int m = 0;
    pw[0] = 1;
    for(i = 1; i <= n; i++){
        pw[i] = pw[i - 1] * 2LL % mod;
        cin >> l >> r;
        seg[++m] = {l, 1, i};
        seg[++m] = {r + 1, -1, i};
        cin >> l >> r;
        seg[++m] = {l, 1, i};
        seg[++m] = {r + 1, -1, i};
    }
    sort(seg + 1, seg + m + 1);
    mp[0] = n;
    int res = 0;
    for(i = 1; i <= m; i++){
        int id = seg[i].id, pos = seg[i].pos, mark = seg[i].mark;
        mp[cnt[id]]--;
        cnt[id] += mark;
        if(mark == 1 && !mp[0]){//只在每个区间开头且当前点被所有组区间覆盖才统计答案
            res = (res + pw[mp[2]]) % mod;
        }
        mp[cnt[id]]++;//先判断是否统计答案再更新mp数组,考虑下面几种情况(假设当前点都被所有组区间覆盖到):
                      //1、当前点是该组区间的第一个区间的开头,那么先统计答案和还是更新mp,没有影响(因为mp[2]不会改变)
                      //2、当前点是该组第二个区间的开头,且第一个区间和第二个区间不相交,那么和1、同理
                      //3、当前点是第二个区间开头,第一个和第二个区间相交,且第一个区间开头(含)到第二个区间开头(不含)的点中有被所有组区间覆盖的,
                      //即第一个区间已经选过,那么此时mp[2]++再统计就会重复
                      //4、当前点是第二个区间开头,第一个和第二个区间相交,且第一个区间开头含)到第二个区间开头(不含)的点中没有有被所有组区间覆盖的,
                      //即第一个区间没有选过,在遍历第一组第一个区间的开头时,此时mp[2]=1,即第二组两个区间各自选的情况都会统计到
        
    }
    cout << res;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__night_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值