离散化贪心不多说了。然后在字典序最小上卡思路……想到了这个题要维护字典序最小的话,就应该按照顺序判断某线段可行与否。该线段[L, R]可行要满足以下两个条件:
1) 这条线段没有接触到任何一个被覆盖的点。
2) 那么这条线段一定落在一个可行区间[L', R']中。设MT(A, B)表示区间[A, B]最多能放几条线段,就必须满足MT(L', L - 1) + MT(R + 1, R') + 1 = MT(L', R')。
如果这条线段可行,那么就输出它,并且把这条线段所在的区间分断成[L', L - 1]和[R + 1, R']。
这个解决方案有这样几个问题没有解决:
首先,查找[L, R]所在区间。这个不多说,直接用平衡树。当然线段树也是可以的。
之后就是MT函数的计算。这可是这个题的精髓所在!
首先我们去掉所有包含其他线段的线段,并按照其L排序。显然这时R也是排好序的。
设RIGHT(x)为从x开始向右走,遇到的第一个区间的右边界加一(若是x右边一个可行区间都没有就返回infinite)。设M(0, x) = RIGHT(x),M(k, x) = RIGHT(M(k - 1, x))。那么,MT(L, R) = max { k | M(K, L) <= R + 1 }。对于这种问题,有一个大杀器可用,那就是倍增。我们首先要预处理一个二维数组jump,使得jump[k][x] = M(2^k, x),预处理这个数组可以用jump[0][x] = RIGHT(x),jump[k][x] = jump[k - 1][jump[k - 1][x]]来做。之后,求MT(L, R)的方法就变得简单啦:首先从高到底枚举i,0->ans,如果jump[i][L] <= R + 1,那么ans + 1<<i -> ans,jump[i][L] -> L,一直做下去直到i = 0计算完毕。这样的复杂度是O(logN)。
总体时间复杂度就是O(NlogN)。
-
#include <cstdio>
-
#include <cstring>
-
#include <cstdlib>
-
#include <vector>
-
#include <set>
-
#include <algorithm>
-
using namespace std;
-
-
const int mi = 19931117;
-
int lsh[500020], lsht[500020], lshmr;
-
void initialize (void)
-
{
-
sort(lsh, lsh + lshmr);
-
int cnt = 0;
-
for (int i = 0; i < lshmr; i++)
-
{
-
if (i == 0 || lsh[i] != lsh[i - 1])
-
lsht[cnt++] = lsh[i];
-
} lshmr = cnt;
-
}
-
inline int place (int a)
-
{
-
int st = 0, ed = lshmr, mid;
-
while (ed - st > 1)
-
{
-
mid = (st + ed) >> 1;
-
if (lsht[mid] > a) ed = mid;
-
else st = mid;
-
} return st + 1;
-
}
-
pair<int, int> require[250010];
-
pair<int, int> rs[250010], trs[250010]; int trmr;
-
bool comp (const pair<int, int>& a, const pair<int, int>& b)
-
{
-
if (a.first != b.first) return a.first < b.first;
-
else return a.second > b.second;
-
}
-
-
int jump[20][500010], maxj;
-
void jump_st (void)
-
{
-
int p = 0; jump[0][lshmr + 1] = mi;
-
for (int i = lshmr; i >= 1; i--)
-
{
-
if (p < trmr && i == trs[p].first) jump[0][i] = trs[p++].second + 1;
-
else jump[0][i] = jump[0][i + 1];
-
}
-
bool valid;
-
for (int i = 1; ; i++)
-
{
-
valid = false;
-
jump[i][lshmr + 1] = mi;
-
for (int k = 1; k <= lshmr; k++)
-
{
-
if (jump[i - 1][k] == mi) jump[i][k] = mi;
-
else jump[i][k] = jump[i - 1][jump[i - 1][k]];
-
if (jump[i][k] < mi) valid = true;
-
}
-
if (valid == false) { maxj = i - 1; break; }
-
}
-
}
-
int max_time (int s, int e)
-
{
-
if (s >= e) return 0;
-
int ts = s, ans = 0; ++e;
-
for (int j = maxj; j >= 0 && ts < e; j--)
-
if (jump[j][ts] <= e) ts = jump[j][ts], ans += (1 << j);
-
return ans;
-
}
-
set<pair<int, int> > query;
-
typedef set<pair<int, int> >::iterator ptr; int ans;
-
bool judge (int i)
-
{
-
int l = require[i].first, r = require[i].second;
-
ptr t1, t2;
-
t1 = query.lower_bound(make_pair(l, mi));
-
if (t1 == query.begin()) return false; else --t1;
-
if (t1->second < l) return false;
-
t2 = --query.lower_bound(make_pair(r, mi));
-
if (t1 != t2) return false;
-
if (t1->second < r) return false;
-
int ll = t1->first, rr = t1->second;
-
int tans = max_time(ll, l - 1) + max_time(r + 1, rr) + 1;
-
int sans = max_time(ll, rr);
-
if (tans < sans) return false;
-
else
-
{
-
query.erase(t1);
-
if (ll <= l - 1) query.insert(make_pair(ll, l - 1));
-
if (r + 1 <= rr) query.insert(make_pair(r + 1, rr));
-
return true;
-
}
-
}
-
int main ()
-
{
-
int n, ans; scanf("%d", &n), lshmr = 0;
-
for (int i = 0; i < n; i++)
-
{
-
scanf("%d %d", &require[i].first, &require[i].second);
-
lsh[lshmr++] = require[i].first;
-
lsh[lshmr++] = require[i].second;
-
}
-
initialize();
-
for (int i = 0; i < n; i++)
-
{
-
int l = place(require[i].first), r = place(require[i].second);
-
require[i].first = l, require[i].second = r;
-
rs[i] = make_pair(l, r);
-
}
-
sort(rs, rs + n, comp), trmr = 0; int p;
-
for (int i = n - 1; i >= 0; i--)
-
{
-
if (i == n - 1 || rs[i].second < rs[p].second)
-
trs[trmr++] = rs[i], p = i;
-
}
-
jump_st();
-
query.insert(make_pair(1, lshmr));
-
printf("%d\n", ans = max_time(1, lshmr));
-
for (int i = 0; i < n; i++)
-
if (judge(i)) printf("%d ", i + 1);
-
printf("\n");
-
return 0;
-
}
-