【题目链接】
http://acm.hdu.edu.cn/showproblem.php?pid=6301
题目意思
让你寻找一个长度为n的最小字典序数组,数组满足m个区间任意两数值不同。
解题思路
用数组pre[i]记录以i为右区间的最左区间,也就是i能覆盖的最大区间。然后用set来记录能使用的数值。从左往右填值。在一个区间的不断弹出数值,如果在区间左边也就是小于pre[i],把之前弹出的数值补回。
注意:如果区间[1,4]不同的话那么2和3的pre也要更新成1.(这样可以去除完全被覆盖的小区间)。实现这一操作只要倒在找min(pre[i],pre[i+1]).
代码部分
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <string>
#include <map>
#include <math.h>
#include <set>
using namespace std;
#define LL long long
#define inf 0x3f3f3f3
const int mod = 1e9+7;
const int N = 1e5+7;
int pre[N]; ///以i为终点覆盖的最大区间
int a[N]; ///存放答案
set<int>q;
int main()
{
int t,n,m;
scanf("%d",&t);
while (t--)
{
scanf("%d %d",&n,&m);
q.clear();
for (int i = 1; i <= n; i++)
{
pre[i] = i;
q.insert(i);
}
for(int i = 0; i < m; i++)
{
int l,r;
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]); ///如输入1,4.那么2,3的下标也跟新成1.去掉完全被覆盖的小区间
int pl = 1; ///标记不重复的起点
for (int i = 1; i <= n; i++)
{
while (pl < pre[i]) ///区间的最左比起点大,把之前使用的数值补回
{
q.insert(a[pl]);
pl++;
}
a[i] = *q.begin();
q.erase(a[i]);
}
for (int i = 1; i <= n; i++)
printf("%d%c",a[i]," \n"[i==n]);
}
return 0;
}