题目链接:1004 Distinct Values
题目大意
一个数列, 长度为n, 有m个特征[l, r], 表示区间内所有数字都不重复
思路
用一个数组pre[i], 表示上一次数字i在数组中出现的位置
将所有特征排序, 先按l从小到大排序, 如果l相同, 按r从大到小排序(这样如果区间相互包含的情况只需要处理一次最大的那个区间, 小的区间跳过就好了)
然后遍历所有特征, 对于每个特征遍历1-n, 如果当前数字i上次出现的位置pre[i]>=l, 说明这个数字在这个区间出现过了, ++i, 直到遇到一个没有出现的数字, 处理完所有区间后, 再把没有被任何区间覆盖的位置都填上1
复杂度n*m, 数据太弱了, 只要有一组数据是(l, r), (l+1, r+2), (l+2, r+4)….这个样子的, 就会TLE, 然后还是AC了, 这场真的有毒
正确的做法应该是用一个set或者优先队列记录所有没有出现的数, 一开始set中存了1-n所有数字, 将
排序后, 逐个处理, 每次将set中最小的数字放到当前位置, 然后erase这个数字, 处理完
后, 将
中的所有数字再insert进去
代码
本应TLE却AC的代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 1e5 + 100;
typedef long long ll;
typedef pair<int, int> P;
P p[maxn];
int T;
int n, m;
bool cmp(const P&x, const P&y)
{
if(x.first == y.first) return y.second > x.second;
return x.first < y.first;
}
int pre[maxn];
int ans[maxn];
int main()
{
for(scanf("%d", &T); T; --T)
{
scanf("%d%d", &n, &m);
for(int i=1; i<=m; ++i)
{
scanf("%d%d", &p[i].first, &p[i].second);
}
memset(pre, 0, sizeof(int)*(n+10));
memset(ans, 0, sizeof(int)*(n+10));
sort(p+1, p+1+m);
// for(int i=1; i<=m; ++i) cout << p[i].first << "*" << p[i].second << endl;
int last = 0;
for(int i=1; i<=m; ++i)
{
if(p[i].second<=last) continue;
int v = 1;
for(int j=max(last+1, p[i].first); j<=p[i].second; ++j)
{
while(pre[v]>=p[i].first) ++v;
ans[j] = v++;
pre[v-1] = j;
}
last = max(last, p[i].second);
}
for(int i=1; i<=n; ++i)
{
if(ans[i] == 0) ans[i] = 1;
}
for(int i=1; i<=n; ++i)
{
printf("%d%c", ans[i], i==n ? '\n' : ' ');
}
}
return 0;
}