zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    linux top详解
    软件人才必须具备的素质
    合格程序员每天每周每月每年应该做的事
    正则匹配任意字符(包括换行)
    软件测试方案
    LInux进程间的通信方式有哪儿些?
    三网融合
    php路径问题
    xp 安装SATA AHCI驱动
    进程与线程的区别
  • 原文地址:https://www.cnblogs.com/stoorz/p/14893685.html
Copyright © 2011-2022 走看看