题意:
给定n段区间,要求每段区间内没有重复的数字; 构造这样一个序列,使得序列的字典序最小
思路:
字典序最小的话我们可以想到 对序列从左往右放数,从1开始放数;
然后按n个序列的左值排序,这样我们只需要考虑相邻的两个区间就好,当前区间和上一个区间,
这里分为以下情况:
如果当前区间包含在前一个区间,则不用考虑,continue;
如果当前区间跟前一个区间没有交集,则不需要在考虑前面的区间;
如果有交集,则只考虑交集部分,前面不想交的部分可以忽略;
这样就产生一个怎么放数的问题,我们先用优先队列存1-n,表示当前区间可以放置的数字,再用queue按顺序存前一个区间正在用的数字,再根据上面三种情况,选择是否或者把queue中哪一部分放入优先队列;
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int INF = 0x7f7f7f7f;
const int maxn = 1e5 + 7;
int n, m;
int ans[maxn];
priority_queue<int, vector<int>, greater<int> > q;
queue<int> t;
struct node {
int l, r;
}a[maxn];
bool cmp(node a, node b) {
if(a.l == b.l) {
return a.r > b.r;
}
else return (a.l<b.l);
}
int main() {
int T; scanf("%d", &T);
while(T--) {
int n, m; scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
ans[i] = 1;
}
for(int i = 0; i < m; ++i) {
scanf("%d%d", &a[i].l, &a[i].r);
}
sort(a,a+m,cmp);
while(!q.empty()) q.pop();
while(!t.empty()) t.pop();
for(int i = 1; i <= n; ++i) {
q.push(i);
}
int xl = a[0].l, xr = a[0].r;
for(int i = xl; i <= xr; ++i) {
ans[i] = q.top(); q.pop();
t.push(ans[i]);
}
for(int i = 1; i < m; ++i) {
int nl = a[i].l, nr = a[i].r;
if(nr <= xr) continue;
else if(nl > xr) {
while(!t.empty()) {
int tt = t.front(); t.pop();
q.push(tt);
}
xl = nl; xr = nr;
for(int i = xl; i <= xr; ++i) {
ans[i] = q.top(); q.pop();
t.push(ans[i]);
}
}
else {
for(int i = xl; i < nl; ++i) {
int tt = t.front(); t.pop();
q.push(tt);
}
for(int i = xr+1; i <= nr; ++i) {
ans[i] = q.top(); q.pop();
t.push(ans[i]);
}
xl = nl; xr = nr;
}
}
for(int i = 1; i <= n; ++i) {
printf("%d%c", ans[i], (i == n?'\n':' '));
}
}
return 0;
}