题目链接:Distinct Values
题意
构造一个长度为 n n 的正整数序列,要求这个序列内对于所有给定的 个区间 [li,ri] [ l i , r i ] ,都满足区间内所有数字两两互不相等,求字典序最小的合法序列。
输入
第一行为一个整数 T T ,接下去 组数据,每组数据第一行为两个整数 n,m (1≤n,m≤105) n , m ( 1 ≤ n , m ≤ 10 5 ) ,接下去 m m 行每行两个整数 ,数据保证所有 n n 和 至少一个的和不超过 106 10 6 。
输出
输出一个长度为 n n 的合法序列。
样例
输入 |
---|
3 2 1 1 2 4 2 1 2 3 4 5 2 1 3 2 4 |
输出 |
1 2 1 2 1 2 1 2 3 1 1 |
题解
将所有区间按 为主关键字, ri r i 为次关键字排序,然后 O(n) O ( n ) 预处理出每个数字对应的最靠前的左区间下标 headi h e a d i ,如果某个点不在任何一个区间内,则 headi=i h e a d i = i ,然后先把 1 1 到 所有数字放到小顶堆内,从前往后扫,每次取出堆顶的值放入当前位置,如果出现 headi≠headi+1 h e a d i ≠ h e a d i + 1 ,就先将区间 [headi,headi+1) [ h e a d i , h e a d i + 1 ) 内的所有放下去的数字收回到小顶堆,就可以得到答案。
过题代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 100000 + 100;
struct Node {
int l, r;
};
bool operator<(const Node &a, const Node &b) {
return (a.l == b.l? a.r < a.r: a.l < b.l);
}
int T, n, m;
Node node[maxn];
int ans[maxn], head[maxn];
priority_queue<int, vector<int>, greater<int> > que;
int main() {
#ifdef Dmaxiya
freopen("test.txt", "r", stdin);
#endif // Dmaxiya
ios::sync_with_stdio(false);
scanf("%d", &T);
while(T--) {
while(!que.empty()) {
que.pop();
}
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
head[i] = i;
que.push(i);
}
for(int i = 0; i < m; ++i) {
scanf("%d%d", &node[i].l, &node[i].r);
}
sort(node, node + m);
int End = 1;
for(int i = 0; i < m; ++i) {
End = max(End, node[i].l);
while(End <= node[i].r) {
head[End] = node[i].l;
++End;
}
}
ans[1] = 1;
que.pop();
for(int i = 2; i <= n; ++i) {
if(head[i] != head[i - 1]) {
for(int j = head[i - 1]; j < head[i]; ++j) {
que.push(ans[j]);
}
}
ans[i] = que.top();
que.pop();
}
for(int i = 1; i <= n; ++i) {
if(i != 1) {
printf(" ");
}
printf("%d", ans[i]);
}
printf("\n");
}
return 0;
}