hdu-6301-思路贪心

这个题如果从直接的想法做很简单,但是时间肯定过不去,难处理的在于如何把用完了的数字重新利用

这个题解是dls的代码,大体思路是用pre[i]记录i所在的区间的左端点,然后设置一个标记用来记录已经处理完的位置(不是填完数字的位置,是既填完了数字又将可利用的数字处理完了的位置),当标记小于pre[i]时表明:从标记到新的区间左端这个区间的数字可以重新利用了,然后用set回收一下。这样就解决了这个问题。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <set>

using namespace std;

const int maxn=100000;
int t,n,m,l,r;
int ans[maxn+5],pre[maxn+5];
set<int> st;

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        st.clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) pre[i]=i;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&l,&r);
            pre[r]=min(pre[r],l);//记录每个区间,即以r为右端点的区间的左端点是l
        }
        for(int i=n-1;i>=1;i--) pre[i]=min(pre[i],pre[i+1]);//从后面开始将记录的左端点展开
        //最终使得pre数组记录的是到达点i的区间是从哪个端点开始的,即i所在的区间的左端点是pre[i]
        int p1=1;//记录可利用的数字的区间的左端点
        for(int i=1;i<=n;i++) st.insert(i);
        for(int i=1;i<=n;i++)
        {
            while(p1<pre[i])//每次当标记小于当前这个区间的左端点时,表示从标记到左端点前的数字都可以在新的区间里使用了
            {
                st.insert(ans[p1]);
                p1++;
            }
            ans[i]=*st.begin();
            st.erase(ans[i]);
        }
        for(int i=1;i<=n;i++)
            printf("%d%c",ans[i]," \n"[i==n]);//大佬的操作,学到了就膜一蛤Orz
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/alusang/article/details/81190864