计蒜客 微软项目经理的挑选方案

n(20w) 个区间 [li,ri] (1li,ri109) ,要求对于所有未选中的区间都存在选中的区间与之有交集,求方案数 mod(109+7)

引用官方题解:
考虑 dp 的做法,首先把所有线段按照右端点排序,右端点相同的按照左端点排序,然后从 1 到 n 重新给线段标号。
定义 R(i) 表示线段 i 后面,最小的未被支配的线段下标,如果不存在的话令 R(i)=n+1 。定义 L(i) 表示线段 i 前面,最大的未被 i 支配的线段下标,如果不存在,令 L(i)=0

PS:没来由的 BZOJ 1835: [ZJOI2010]base 基站选址 既视感
线段树+dp

#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<bitset>
#include<cassert>
#include<cstring>
#include<complex>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
#define inf (1<<30)
#define INF (1ll<<62)
#define y1 bflaisfnmasf
#define y2 fsafgmalg
#define tm afnsjkf
#define j1 sfakf
#define j2 fasndfkas
#define fi first
#define se second
#define CLR(x,f) memset(x,f,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define prt(x) cout<<#x<<":"<<x<<" "
#define prtn(x) cout<<#x<<":"<<x<<endl
#define huh(x) printf("--------case(%d)--------\n",x)
#define travel(x) for(Edge *e=h[x];e;e=e->n)
#define TLE
#define HDUE
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;

const int M=200005;
const ll mod=1e9+7;
int n;

struct range{
    int l,r;
    bool operator<(const range&a)const{
        return r==a.r?l<a.l:r<a.r;
    }
}d[M];

int lx[M],rx[M];
struct node{
    ll sum,mul,add;//区间乘,区间加
    int sz;
    node operator+(const node&a)const{
        return (node){(sum+a.sum)%mod,1,0,sz+a.sz};
    }
};
struct Segment{
    node v[M<<2];
    #define ls (x<<1)
    #define rs (x<<1|1)
    void down(int x){
        if(v[x].mul!=1||v[x].add){
            adjust(ls,v[x].mul,v[x].add);
            adjust(rs,v[x].mul,v[x].add);
            v[x].mul=1;v[x].add=0;
        }
    }
    void up(int x){
        v[x]=v[ls]+v[rs];
    }
    void adjust(int x,ll mul,ll add){
        v[x].sum=v[x].sum*mul+add*v[x].sz;
        v[x].add=v[x].add*mul+add;
        v[x].mul=v[x].mul*mul;
        v[x].sum%=mod;
        v[x].mul%=mod;
        v[x].add%=mod;
    }
    void update(int x,int l,int r,int L,int R,ll mul,ll add){
        if(L<=l&&r<=R){
            adjust(x,mul,add);
            return;
        }
        int mid=l+r>>1;
        down(x);
        if(L<=mid)update(ls,l,mid,L,R,mul,add);
        if(R>mid)update(rs,mid+1,r,L,R,mul,add);
        up(x);
    }
    void Add(ll &x,ll y){
        if((x+=y)>=mod)x-=mod;
    }

    ll query(int x,int l,int r,int L,int R){
        if(L<=l&&r<=R)return v[x].sum;
        down(x);
        ll res=0;
        int mid=l+r>>1;
        if(L<=mid)Add(res,query(ls,l,mid,L,R));
        if(R>mid)Add(res,query(rs,mid+1,r,L,R));
        return res;
    }
    void build(int x,int l,int r){
        if(l==r){
            v[x].sz=1;
            v[x].mul=1;
            return;
        }
        int mid=l+r>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        up(x);
    }
}sgm;

int main(){

    scanf("%d",&n);

    for(int i=1;i<=n;i++)
        scanf("%d%d",&d[i].l,&d[i].r);
    sort(d+1,d+n+1);

    int top=1;
    for(int i=1;i<=n;i++){
        while(d[top].r<d[i].l)rx[top++]=i;
        rx[i]=n+1;
        lx[i]=lower_bound(d,d+i+1,(range){0,d[i].l})-d-1;
    }
//  update(int x,int l,int r,int L,int R,ll mul,ll add)
//  query(int x,int l,int r,int L,int R)
    sgm.build(1,0,n);
    sgm.update(1,0,n,0,0,1,1);
    for(int i=1;i<=n;i++){
        sgm.update(1,0,n,rx[i]-1,n,2,0);
        if(lx[i])sgm.update(1,0,n,0,lx[i]-1,2,0);//* really important 
        ll res=sgm.query(1,0,n,lx[i],rx[i]-2);
        sgm.update(1,0,n,rx[i]-1,rx[i]-1,1,res);
    }
    printf("%lld\n",sgm.query(1,0,n,n,n));
    return 0;
}
/*
5
1 8
7 9
4 6
5 7
2 3
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值