1.​​题目链接​​。题目大意:一个长度为n的数组,现在对这个数组做一些限制:在区间[l,r]里面不能有相同的数出现。输出满足条件并且字典序最小的那个数组。

2.思路有很多,不过发现可行的不是很多。大佬的队友用并查集写过了(神仙,完全想不到并查集的思路)。最后的做法就是:对于每一个数据,用pre[i]记录一下与当前的这个点i不能出现相同的数据的最左边的那个位置。也就是pre[i]=min(pre[i],l)注意这里时min,因为在左边,我们要取到最长,一定是去最小的那个。这样一些小的区间其实就被覆盖掉了。然后用pl,set,ret分别维护当前已经完成填充的区间的右端点,当前可以用的元素,以及答案。这样,对于每一个i,我们找到pre[i],比较pre[i]和pl的大小,如果pl<pre[i]表示还是由比较多的元素可以继续使用,我们我们把上一次放在ret里面的东西拿出来再次丢进set,然后ret[i]就是set的起始元素,这里其实就保证了字典序最小,因为set是红黑树,所以里面的元素都是有序的排列的。然后把答案记录一下,在set里面移除这个元素。最后输出即可。

#include<bits/stdc++.h>
using namespace std;
#pragma warning(disable:4996)
const int N = 100100;
int t, n, m, pre[N], l, r, ret[N];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
pre[i] = i;
}
for (int i = 0; i < m; i++)
{
scanf("%d%d", &l, &r);
pre[r] = min(pre[r], l);
}
for (int i = n - 1; i >= 1; i--)
{
pre[i] = min(pre[i], pre[i + 1]);
}
int pl = 1;
set<int>val;
for (int i = 1; i <= n; i++)
{
val.insert(i);
}
for (int i = 1; i <= n; i++)
{
if (pl < pre[i])
{
while (pl < pre[i])
{
val.insert(ret[pl++]);
}
}
ret[i] = *val.begin();
val.erase(ret[i]);
}
for (int i = 1; i <= n; i++)
{
if (i != 1)
cout << " ";
cout << ret[i];
}
puts("");
}
return 0;
}