传送门:HDU 6301
Problem Description
Chiaki has an array of n positive integers. You are told some facts about the array: for every two elements ai and aj in the subarray al…r (l≤i<j≤r), ai≠aj holds.
Chiaki would like to find a lexicographically minimal array which meets the facts.
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains two integers n and m (1≤n,m≤105) – the length of the array and the number of facts. Each of the next m lines contains two integers li and ri (1≤li≤ri≤n).
It is guaranteed that neither the sum of all n nor the sum of all m exceeds 106.
Output
For each test case, output n integers denoting the lexicographically minimal array. Integers should be separated by a single space, and no extra spaces are allowed at the end of lines.
Sample Input
3
2 1
1 2
4 2
1 2
3 4
5 2
1 3
2 4
Sample Output
1 2
1 2 1 2
1 2 3 1 1
题意:
有t组测试数据,每组数据让你输出n个数,对这n个数有m个要求 , 每个要求区间里面的数各不相等。要你输出字典序列最小的那个。
比如第三个样例: 5个数,2个区间 : [1,3] [2,4]
首先安排 1~3 的区间,字典序最小且不重复,当然是 1 2 3 了
然后安排 2~4 的区间,2、3 号位已经放了 2、3 了,第四个位置只要不为 2 和 3 即可,那么放 1,最后没限定,要最小所以放 1
所以最后答案是1 2 3 1 1
题解:
这道题思路是去掉重复的区间。
用优先队列或者set模拟维护1-n 中没有出现的数。
(set默认由小到大排序,且不会重复。用set保存当前能插入的元素,这样就能直接插入最小元素了。)
last[i]存以i为起点的最大区间(即求最大右范围)。
详情见代码。
这里模拟一下:
比如给你一个样例
10 3
2 8
1 5
6 10
last数组为 5 8 3 4 5 10 7 8 9 10
把1 到 10 放进set后,[1 5] 这个区间先,所以先从set里取放入a数组 1 2 3 4 5,此时容器里剩下6 7 8 9 10,下个区间 [2 8] ,我们先把a数组的[ 1 2 )这个区间也就是上次和这次不会重复的区间的数丢到set里面去。现在set里剩下 1 6 7 8 9 10 ,需要从里面取出8 - 5= 3个数,即1 6 7,所以结果现在是1 2 3 4 5 1 6 7 。如果a数组中的数大于last[i],就跳过无须操作。直到下个区间[ 6 10 ] ,a数组的[2 6)这个区间的数进set,也就是 2 3 4 5 这四个数。再从这四个数取 2 个,所以答案是
1 2 3 4 5 1 6 7 2 3
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<stack>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=110000;
int t,n,m;
int last[N];//存以i为起点的要求的最大区间
int a[N];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) last[i]=i;
int l,r;
for(int i=0;i<m;i++)
{
scanf("%d%d",&l,&r);
last[l]=max(last[l],r);
}
set<int> v;
for(int i=1;i<=n;i++) v.insert(i);
l=1,r=0;
//r表示已经构造完成的长度
//l指上一个区间的起点
for(int i=1;i<=n;i++)
{
if(r>last[i]) continue;//排过的不用排
while(l<i)//不重复的区间[l,i)
{
v.insert(a[l]);
l++;
}
while(r<last[i])
{
a[++r]=*v.begin();//从头取
v.erase(a[r]);//并删除这个元素
}
}
for(int i=1;i<=n;i++)
{
printf("%d%c",a[i],i==n?'\n':' ');
}
}
return 0;
}