CF730G Car Repair Shop

题意

nn 个请求,每次请求一个区间 [si,si+di1][s_i,s_i+d_i-1]

  • 如果该区间完全没有被占用,占用该区间。

  • 如果该区间有位置已经被占用,占用另一个长度为 sis_i,左端点最小的且完全未被占用的区间。

求出每个请求占用的区间。

分析

我们需要进行的操作有:

  • 查询某个区间是否被用过。

  • 插入某个已知边界的区间。

  • 插入某个已知长度的区间。

由于有插入操作的存在,所以我们需要一个支持在任意位置插入元素、查询元素的数据结构,可以看到 nn 最大只有 200200,所以我们可以使用链表来实现。

struct Q{
	int nxt;//下一个节点
	ll l,r;//左右边界
}a[N];

初始化

一开始,令整个链表只有两个节点 0011,分别是起点和终点,节点 00 中的区间是 [0,0][0,0],节点 11 中的区间是 [1010,1010][10^{10},10^{10}],由题目中的数据可以算出题目所用的区间一定在这两个之间。

a[0].l=a[0].r=0;
a[1].l=a[1].r=1ll*1e5*1e5;
a[0].nxt=1;
a[1].nxt=0;

查询某个区间是否被用过

设查询 [l,r][l,r] 是否被占用。

依次遍历每个节点,如果某个区间 ii 满足以下条件,说明它查询区间被占用,立即结束。

  • a[i].lla[i].l\le lla[i].rl\le a[i].r[l,r][l,r] 的左部分被别的区间占用。

  • a[i].lra[i].l\le rra[i].rr\le a[i].r[l,r][l,r] 的右部分被别的区间占用。

  • la[i].ll\le a[i].la[i].rra[i].r\le r[l,r][l,r] 的中部分被别的区间占用。

bool find(ll l,ll r){
	for(int i=a[0].nxt;i;i=a[i].nxt)
		if((l>=a[i].l&&l<=a[i].r)||(r>=a[i].l&&r<=a[i].r)||(l<=a[i].l&&r>=a[i].r))
			return 1;
	return 0;
}

插入某个已知边界的区间

设插入区间 [l,r][l,r]

依次遍历每个节点 ii,并记录它的下一个节点 jj,如果 [l,r][l,r] 在两个区间之间的区间中,即 a[i].r<la[i].r<lr<a[j].lr<a[j].l,就插入这个区间。

注意新的区间可能比之前的更小,所以遍历要从 00 节点开始

void insert1(ll l,ll r){
	for(int i=0;a[i].nxt;i=a[i].nxt){
		int j=a[i].nxt;
		if(a[i].r<l&&r<a[j].l){
			a[++t].l=l;
			a[t].r=r;
			a[i].nxt=t;
			a[t].nxt=j;
			return;
		}
	}
}

插入某个已知长度的区间

设插入区间长度为 lenlen

同样依次遍历每个节点 ii,并记录它的下一个节点 jj,如果这两个区间之间的区间大于等于 lenlen 的,即 a[j].la[i].r1lena[j].l-a[i].r-1\ge len,就插入这个区间,并用 al,aral,ar 记录答案。

同样注意新的区间可能比之前的更小,所以遍历要从 00 节点开始

void insert2(ll len){
	for(int i=0;a[i].nxt;i=a[i].nxt){
		int j=a[i].nxt;
		if(a[j].l-a[i].r-1>=len){
			al=a[++t].l=a[i].r+1;
			ar=a[t].r=a[t].l+len-1;
			a[i].nxt=t;
			a[t].nxt=j;
			return;
		}
	}
}

时间复杂度 O(n2)O(n^2)

代码

#include<bits/stdc++.h>
#define ll long long
#define ld long double
using namespace std;
const int N=210;
int n,t=1;
ll s,d,al,ar;
struct Q{
	int nxt;
	ll l,r;
}a[N];
bool find(ll l,ll r){
	for(int i=a[0].nxt;i;i=a[i].nxt)
		if((l>=a[i].l&&l<=a[i].r)||(r>=a[i].l&&r<=a[i].r)||(l<=a[i].l&&r>=a[i].r))
			return 1;
	return 0;
}
void insert1(ll l,ll r){
	for(int i=0;a[i].nxt;i=a[i].nxt){
		int j=a[i].nxt;
		if(a[i].r<l&&r<a[j].l){
			a[++t].l=l;
			a[t].r=r;
			a[i].nxt=t;
			a[t].nxt=j;
			return;
		}
	}
}
void insert2(ll len){
	for(int i=0;a[i].nxt;i=a[i].nxt){
		int j=a[i].nxt;
		if(a[j].l-a[i].r-1>=len){
			al=a[++t].l=a[i].r+1;
			ar=a[t].r=a[t].l+len-1;
			a[i].nxt=t;
			a[t].nxt=j;
			return;
		}
	}
}
int main(){
	a[0].l=a[0].r=0;
	a[1].l=a[1].r=1ll*1e5*1e5;
	a[0].nxt=1;
	a[1].nxt=0;
    cin>>n;
    for(int i=1;i<=n;i++){
    	cin>>s>>d;
    	if(find(s,s+d-1)){
    		insert2(d);
    		cout<<al<<" "<<ar<<endl;
		}
		else{
			insert1(s,s+d-1);
			cout<<s<<" "<<s+d-1<<endl;
		}
	}
	return 0;
}
posted @ 2021-08-13 14:18  luckydrawbox  阅读(9)  评论(0)    收藏  举报  来源