n(≤20w) 个区间 [li,ri] (1≤li,ri≤109) ,要求对于所有未选中的区间都存在选中的区间与之有交集,求方案数 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
*/