题意:给你一个区间的长度n和m个限制条件的区间,m个区间中的数字不能重复,问此区间字典树最小的方法是什么。
这题在多校的时候,本来以为能水过去,想想当时还是太天真了,这题没仔细考虑的话,以我原来的做法有好多bug,根本改不完,后来看了一下大佬的代码。。还是疯狂wa,。。看这题看了好久啊。。越来越没效率了。。。
思路:首先我们要知道区间不重复出现数字,最简单的方法并且最好用的方法就是用set函数进行存储可以用的数字,每次使用数字,从set里提取出来再删掉就行了。其它的看注释吧。
AC代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
using namespace std;
const int maxn = 1e5+10;
int ends[maxn],col[maxn]; //ends[i],记录以i为起点的的最大结尾为多少。 col,记录每个位置的数字。
int main(){
int t, n, m, i;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
memset(ends, -1, sizeof(ends));
for(i = 1; i <= n; i++)
ends[i] = i; //初始化,把每个点都看成以自己开始自己结束的一个区间。这里很重要。
for(i = 1; i <= m; i++){
int l, r;
scanf("%d%d",&l,&r);
ends[l] = max(ends[l],r); //判断此前是否出现更大的区间范围
}
set<int> s; //记录可以使用的数字
for(i = 1; i <= n; i++) //把1~n都存入set
s.insert(i);
int l = 1, r = 0;
for(i = 1; i <= n; i++){ //判断每个区间,i就是每个区间的起始点
if(r >= ends[i]) //ends[i]的区间已经被更新过,跳过
continue;
while(l < i) //起始点i之前使用过的数字都变为可行数字,加入set
s.insert(col[l++]);
while(r < ends[i]){ //更新当前区间的col
col[++r] = *s.begin();
s.erase(col[r]);
}
}
for(i = 1; i <= n; i++){
if(i-1)
putchar(' ');
printf("%d",col[i]);
}
puts("");
}
return 0;
}