原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=6301
题意:给你一个长度n,然后给出m个要求,每个要求包含l,r两个参数,在 [l,r] [ l , r ] 这个区间内的数互不相同,让你构造这样一个序列,使得字典序最小。
思路:用set维护可以使用的数值,然后使用两个指针指示上一个区间包含的范围。然后就可以像莫队一样将指针移动。
注意可能会有两个区间互不重合的情况。
具体看代码吧
#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 5;
int t, n, m, l, r;
struct node {
int l, r;
bool operator < (const node &a)const {
if(l == a.l) return r < a.r;
else return l < a.l;
}
} e[maxn];
int ans[maxn];
int main() {
scanf("%d", &t);
while(t--) {
set<int>st;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
scanf("%d%d", &e[i].l, &e[i].r);
}
sort(e + 1, e + 1 + m);//按l的大小排序
for(int i = 1; i <= n; i++) {
st.insert(i);
ans[i] = 1;//初始化为1,因为要最小的字典序
}
for(int i = e[1].l; i <= e[1].r; i++) {
ans[i] = *st.begin();
st.erase(st.begin());
}
int l = e[1].l;
int r = e[1].r;
for(int i = 2; i <= m; i++) {
if(e[i].l >= e[i - 1].l && e[i].r <= e[i - 1].r) continue;//去掉被大区间包含的小区间
while(l < e[i].l) {//因为已经经过了排序,所以并不需要像莫队那样写4个while
st.insert(ans[l++]);
}
while (r < e[i].r) {//注意考虑[1,3][6,8]这样的两个区间,这个时候需要的是++r
if(r >= e[i].l - 1) {
ans[++r]=*st.begin();
st.erase(st.begin());
}
else ++r;
}
}
for(int i = 1; i < n; i++) {
printf("%d ", ans[i]);
}
printf("%d\n", ans[n]);
}
return 0;
}