[CF1523G]Try Booking

Try Booking

题解

树套树板子题

我们可以对于 i ∈ [ 1 , n ] i\in[1,n] i[1,n]的每个情况,都去寻找它会选取那些订单。
很明显,它选取的订单不会超过 ∑ i = 1 n ⌊ n i ⌋ = l n   n \sum_{i=1}^{n}\left\lfloor\frac{n}{i}\right\rfloor=ln\,n i=1nin=lnn

对于每个 i i i,我们可以都先找一下我对于区间 [ 1 , n ] [1,n] [1,n]中,会先选取哪一个订单。
选取后,当前区间会断裂成两个子区间,我们在递归下去,寻找在该子区间中我们会先选取那个订单。
很明显,对于任意一个区间,我们都会首先去找这个区间中长度不小于 i i i的编号最小的一个订单,也就是说,我们需要一个数据结构去对其进行维护。
对于长度不小于 i i i这个条件,我们可以先将其离线下来,按长度从大到小依次加入订单,再在当前所需要的区间中寻找编号最小的订单。
寻找订单的操作,我们可以通过一个线段树套线段树来维护,外层线段树维护左端点的区间,内层线段树维护右端点的的区间中编号的最小值。

很明显查操作与修改操作都是 O ( l o g 2 n ) O\left(log^2n\right) O(log2n)的。
而我们总共会进行 n l n   n nln\,n nlnn次询问与 m m m次修改,所以总时间复杂度为 O ( n l o g 2   n l n   n + m l o g 2   n ) O\left(nlog^2\,nln\,n+mlog^2\,n\right) O(nlog2nlnn+mlog2n)
注意内层区间线段树的点数要开大点,达到 m l o g 2 n mlog^2n mlog2n的级别,不然会TLE 毕竟RE爆什么都有可能,笔者就TLE了

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 50005
#define MAXM 100005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int zero=500;
const LL jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,m,root[MAXN<<2],ans[MAXN];
struct node{int l,r,id;}s[MAXM],p[MAXM];
struct ming{int lson,rson,mn;ming(){lson=rson=0;mn=1e5+1;}};
bool cmp(node x,node y){return x.r-x.l>y.r-y.l;}
class SegmentTree{
	public:
		int tot;ming tr[MAXM*200];
		void insert(int &rt,int l,int r,int ai,int id){
			if(l>r||l>ai||r<ai)return ;if(!rt)rt=++tot;int mid=l+r>>1;
			tr[rt].mn=min(tr[rt].mn,id);if(l==r)return ;
			if(ai<=mid)insert(tr[rt].lson,l,mid,ai,id);
			if(ai>mid)insert(tr[rt].rson,mid+1,r,ai,id);
		}
		int query(int rt,int l,int r,int ai){
			if(l>r||l>ai||!rt)return m+1;
			if(r<=ai)return tr[rt].mn;int mid=l+r>>1,res=m+1;
			if(ai<=mid)res=query(tr[rt].lson,l,mid,ai);
			else res=min(tr[tr[rt].lson].mn,query(tr[rt].rson,mid+1,r,ai));
			return res;
		}
}T;
void insert(int rt,int l,int r,int ai,int pos,int id){
	if(l>r||l>ai||r<ai)return ;int mid=l+r>>1;
	T.insert(root[rt],1,n,pos,id);if(l==r)return ;
	if(ai<=mid)insert(rt<<1,l,mid,ai,pos,id);
	if(ai>mid)insert(rt<<1|1,mid+1,r,ai,pos,id);
}
int query(int rt,int l,int r,int al,int ar){
	if(l>r||al>ar||l>ar||r<al)return m+1;int mid=l+r>>1,res=m+1;
	if(al<=l&&r<=ar)return T.query(root[rt],1,n,ar);
	if(al<=mid)res=min(query(rt<<1,l,mid,al,ar),res);
	if(ar>mid)res=min(query(rt<<1|1,mid+1,r,al,ar),res);
	return res;
}
void sakura(int l,int r,int lim){
	if(r-l+1<lim||l>r)return ;int id=query(1,1,n,l,r);
	if(id<1||id>m)return ;ans[lim]+=p[id].r-p[id].l+1;
	sakura(l,p[id].l-1,lim);sakura(p[id].r+1,r,lim);
}
signed main(){
	read(n);read(m);
	for(int i=1;i<=m;i++)read(s[i].l),read(s[i].r),s[i].id=i,p[i]=s[i];
	sort(s+1,s+m+1,cmp);int id=1;
	for(int i=n;i>0;i--){
		while(id<=m&&s[id].r-s[id].l+1>=i)
			insert(1,1,n,s[id].l,s[id].r,s[id].id),id++;
		sakura(1,n,i);
	}
	for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
	return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值