题意:多组数据,每组数据 n n n 个数,每组数据给出 m m m 个区间,对于每个区间,区间内所有数都互不相等。求一种给 n n n 个数设置值,且这个值 x x x 在 [ 1 , n ] [1,n] [1,n] 内的方法,若有多种,求字典序最小的一种。
思路:
1.先考虑字典序最小,对于当前要填数字的这一位数,我们在它所能填写的数中选数字最小的,然后考虑下一位,即可保证求出来的答案是字典序最小的了。
2.求当前位置能填的数字,对每个位置设置一个 p r e pre pre 的数组,存放其位置所处的区间中最左边的端点,那么只要是不属于最左边端点到这个位置前一个位置上的数字都可以填,用优先队列来维护这些数字,填入的数字出队,不属于最左边端点到这个位置前一个位置上且不在队列中的数字入队即可。
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
#define NUM 100005
int n, m, T;
int a[NUM], pre[NUM];
int num[NUM];
priority_queue<int, vector<int>, greater<int> > q;
inline void AC()
{
cin >> T;
int p, l, r;
while(T--)
{
cin >> n >> m;
while(!q.empty())
q.pop();
for (int i = 1; i <= n; ++i)
{
num[i] = 0, q.push(i);
pre[i] = i;//初始化:相当于有n个长度为1的区间
}
p = 1;//指向上一个位置所在区间没有覆盖到的最右边的位置
while (m--)
{
scanf("%d%d", &l, &r);
pre[r] = min(pre[r], l);//求以当前位置为右端点的最左边端点
}
for (int i = n - 1; i > 0; --i)//求每个位置所在区间的最左边端点
pre[i] = min(pre[i], pre[i + 1]);
for (int i = 1; i <= n; ++i)
{
while (p < pre[i])//更新,从上一个最右边位置到当前最右边位置中可以填入的数字
{
--num[a[p]];
if (num[a[p]] == 0)
q.push(a[p]);
++p;
}
a[i] = q.top(), q.pop(), ++num[a[i]];//弹出可以填的最小的数字
printf("%d", a[i]);
if (i != n)
printf(" ");
}
printf("\n");
}
}
int main()
{
AC();
return 0;
}