【CF1523G】Try Booking

题目

题目链接:https://codeforces.com/problemset/problem/1523/G
William 想在之后的 (n) 天内出租他的公寓。有 (m) 个请求待 William 依次处理,对于第 (i) 个请求 ([l_i,r_i]) 表示一人想在 ([l_i,r_i]) 天内租借公寓,而这个请求会被接受当且仅当 (r_i-l_i+1ge x)([l_i,r_i]) 这些天内公寓都是空闲的。请对每个 (x=1cdots n) 输出公寓出租的总天数。
(nle 5 imes 10^4, mle 10^5, 1le l_ile r_ile n)

思路

不难发现,对于每一个 (x),同意的请求数量的上界是 (lfloorfrac{n}{x} floor),所以对于 (x=1cdots n),同意的请求数量总数是 (O(nlog n)) 的。
考虑一个很 naive 的做法,对于每一个 (x),我们依次枚举所有请求,如果这个请求可以接受,那么相当于剩余可以被使用的时间分成了两个区间,继续往后枚举解决。
也就是有一个可以使用的时间区间 ([L,R])(初始时为 ([1,n])),我们寻找编号最小的,(r_i-l_i+1geq x),且 (Lleq l_i,r_ileq R) 间的请求 (i),通过这个请求,递归 ([L,l_i),(r_i,R]) 这两个区间继续。
如果我们倒序枚举 (x),相当于需要支持加入新的点 ((l,r)),查询一个子矩阵的编号最小的点。可以用树状数组套线段树解决。
又由于总共通过的请求数量是 (O(nlog n)) 的,所以操作次数也是 (O(nlog n)) 的,时间复杂度为 (O(nlog^3 n+mlog^2 n))

代码

#include <bits/stdc++.h>
using namespace std;

const int N=100010,LG=16,Inf=1e9;
int n,m,rt[N],ans[N],L[N],R[N],id[N];

bool cmp(int x,int y)
{
	return R[x]-L[x]>R[y]-L[y];
}

struct SegTree
{
	int tot,minn[N*LG*4],lc[N*LG*4],rc[N*LG*4];
	SegTree() { memset(minn,0x3f3f3f3f,sizeof(minn)); }
	
	int update(int x,int l,int r,int k,int v)
	{
		if (!x) x=++tot;
		minn[x]=min(minn[x],v);
		if (l==r) return x;
		int mid=(l+r)>>1;
		if (k<=mid) lc[x]=update(lc[x],l,mid,k,v);
			else rc[x]=update(rc[x],mid+1,r,k,v);
		return x;
	}
	
	int query(int x,int l,int r,int ql,int qr)
	{
		if (!x) return Inf;
		if (ql<=l && qr>=r) return minn[x];
		int mid=(l+r)>>1,res=Inf;
		if (ql<=mid) res=min(res,query(lc[x],l,mid,ql,qr));
		if (qr>mid) res=min(res,query(rc[x],mid+1,r,ql,qr));
		return res;
	}
}seg;

struct BIT
{
	void add(int x,int p,int v)
	{
		for (int i=x;i<=n;i+=i&-i)
			rt[i]=seg.update(rt[i],1,n,p,v);
	}
	
	int query(int x,int p)
	{
		int ans=Inf;
		for (int i=x;i;i-=i&-i)
			ans=min(ans,seg.query(rt[i],1,n,p,n));
		return ans;
	}
}bit;

int solve(int l,int r)
{
	int id=bit.query(r,l);
	if (id>=Inf) return 0;
	return solve(l,L[id]-1)+solve(R[id]+1,r)+R[id]-L[id]+1;
}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&L[i],&R[i]);
		id[i]=i;
	}
	sort(id+1,id+1+m,cmp);
	for (int i=n,j=1;i>=1;i--)
	{
		for (;j<=m && R[id[j]]-L[id[j]]+1>=i;j++)
			bit.add(R[id[j]],L[id[j]],id[j]);
		ans[i]=solve(1,n);
	}
	for (int i=1;i<=n;i++) cout<<ans[i]<<"
";
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/14893685.html