hdu 6301 Distinct Values (思维+set)

hdu 6301 Distinct Values

题目传送门

题意:

给你m个区间,让你求出一个长度为n的区间且满足在这些区间的数不重复,

并且要求字典序最小

思路:

如果我们已经求出这个序列了,你会发现,如果大的区间已经满足条件了,

那么它包含的小区间也已经满足了。

然后它要求字典序最小,这个从左往右去填充就行了,每次都有能取的最小的

数去填充进去,这样形成的序列自然符合

所以我们需要一个容器来存储能用的数,假设我们处理完i这个位置,要过度到下一个,

如果i+1还在这个区间还好,如果不在,那么我们就要更新这个容器了,因为此时它

可以选择的数有更多。而我们要增加的数,就是上一个区间与这个区间没有交集的地方

,即两个区间最左端点的刚刚加进去的数。

具体注释看代码。

代码:

#include<bits/stdc++.h>
using namespace std;
int T;
int n,m;
#define N 100005
typedef pair<int,int> PII;
#define fi first
#define se second
PII ipt[N];
int ans[N];
int pre[N];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);

        //初始化
        for(int i=0;i<=n;i++)
        {
            pre[i]=i;
            ans[i]=1;
        }
        //pre记录每个最大区间的左端点
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&ipt[i].fi,&ipt[i].se);
            pre[ipt[i].se]=min(pre[ipt[i].se],ipt[i].fi);
        }

        //把那些零散的点也用包含它的最大区间包括进去
        for(int i=n-1;i>=1;i--)
        {
            if(pre[i]>pre[i+1]) pre[i]=pre[i+1];
        }

        set<int>mu;
        mu.clear();
        for(int i=1;i<=n;i++) mu.insert(i);

        for(int i=1;i<=n;i++)//给每个位置赋值
        {
            for(int j=pre[i-1];j<pre[i];j++)//更新目标集合
            {
                mu.insert(ans[j]);
            }
            ans[i]=*mu.begin();
            mu.erase(mu.begin());
        }

        for(int i=1;i<=n;i++)
        {
            printf("%d%c",ans[i],i==n?'
':' ');
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zhgyki/p/10332026.html