这个题如果从直接的想法做很简单,但是时间肯定过不去,难处理的在于如何把用完了的数字重新利用
这个题解是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;
}