送你一堆区间

68 篇文章 0 订阅
47 篇文章 0 订阅

按区间贪心做惯了,遇到按区间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));
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值