【題目鏈接】
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;
}