HDU 6301 Distinct Values (set)

【题目链接】
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;
}

猜你喜欢

转载自blog.csdn.net/pashuihou/article/details/81181961