按区间贪心做惯了,遇到按区间DP就傻了。
实际上应该按关键点DP,这样计数才更加方便。
至于线段树优化,直接把DP数组看做线段树是不是太。。。。。
ACcode:
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define maxn 500005
#define mod 1000000009
#define lc now<<1
#define rc now<<1|1
#define LL long long
using namespace std;
int n,m;
int l[maxn],r[maxn],c[maxn];
int num[maxn*3],p[maxn];
LL sum[maxn*4],add[maxn*4],mul[maxn*4];
void up(int now){
sum[now]=sum[lc]+sum[rc];
}
void dt(int now){
if(add[now]){
sum[now]=(sum[now]+add[now])%mod;
add[lc]=(add[lc]+add[now])%mod;
add[rc]=(add[rc]+add[now])%mod;
add[now]=0;
}
if(mul[now]!=1){
sum[now]=(sum[now]*mul[now])%mod;
mul[lc]=(mul[lc]*mul[now])%mod;
mul[rc]=(mul[rc]*mul[now])%mod;
mul[now]=1;
}
}
void Add(int now,int l,int r,int pos,LL val){
dt(now);
if(r<pos || l>pos) return;
if(l==r){
add[now]=(add[now]+val)%mod;
dt(now);
return;
}
int m=(l+r)>>1;
Add(lc,l,m,pos,val);
Add(rc,m+1,r,pos,val);
up(now);
}
void Double(int now,int l,int r,int ql,int qr){
dt(now);
if(r<ql || l>qr) return;
if(ql<=l && r<=qr){
mul[now]=(2*mul[now])%mod;
dt(now);
return;
}
int m=(l+r)>>1;
Double(lc,l,m,ql,qr);
Double(rc,m+1,r,ql,qr);
up(now);
}
LL Query(int now,int l,int r,int ql,int qr){
dt(now);
if(r<ql || l>qr) return 0;
if(ql<=l && r<=qr) return sum[now];
int m=(l+r)>>1;
LL ret=Query(lc,l,m,ql,qr)+Query(rc,m+1,r,ql,qr);
up(now);
return ret;
}
bool cmp(const int &a,const int &b){
return l[a]<l[b];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d",&l[i],&r[i]);
c[i]=i;
}
for(int i=1;i<=m;i++)
scanf("%d",&p[i]);
sort(p+1,p+1+m);
for(int i=1;i<=n;i++){
l[i]=lower_bound(p+1,p+1+m,l[i])-p;
r[i]=upper_bound(p+1,p+1+m,r[i])-p-1;
}
for(int i=1;i<=m*4;i++)
mul[i]=1,sum[i]=0;
Add(1,0,m,0,1);
sort(c+1,c+1+n,cmp);
for(int i=1,u;i<=n;i++){
u=c[i];
Add(1,0,m,r[u],Query(1,0,m,l[u]-1,r[u]));
if(r[u]+1<=m)
Double(1,0,m,r[u]+1,m);
}
printf("%lld",Query(1,0,m,m,m));
}