Address
洛谷 P3626
BZOJ 1178
Code
- 先離散化區間端點
- 預處理出對于每個區間 [ l i , r i ] [l_i,r_i] [li,ri] ,滿足 r i < l j r_i<l_j ri<lj 且 r j r_j rj 最小的區間 [ l j , r j ] [l_j,r_j] [lj,rj]
- 下文稱之為「 i i i 的後繼為 j j j 」
- 考慮一個小問題
- 查詢在包含于 [ L , R ] [L,R] [L,R] 的所有區間中,最多能選出多少個互不相交的區間
- 先找到包含于 [ L , R ] [L,R] [L,R] 且右端點最小的區間 [ l i , r i ] [l_i,r_i] [li,ri] (不存在則答案為 0 0 0 )
- 問題轉化為 i i i 至少跳多少次後繼之後右端點超過 R R R 或者不存在後繼
- 倍增 O ( n log n ) O(n\log n) O(nlogn) 預處理後 O ( log n ) O(\log n) O(logn) 查詢
- 考慮貪心地編号從小往大,考慮每個區間是否可以成為答案
- 設目前考慮區間 [ l , r ] [l,r] [l,r]
- 如果 [ l , r ] [l,r] [l,r] 記憶體在一點,已經被之前選出的區間覆寫,則這個區間不能成為答案
- 否則設 l 0 l_0 l0 為滿足 [ l 0 , l ] [l_0,l] [l0,l] 都沒有被覆寫的最小的 l 0 l_0 l0
- r 0 r_0 r0 為滿足 [ r , r 0 ] [r,r_0] [r,r0] 都沒有被覆寫的最大的 r 0 r_0 r0
- 設 q u e r y ( l , r ) query(l,r) query(l,r) 表示包含于 [ l , r ] [l,r] [l,r] 的所有區間中最多選出多少個區間互不相交
- 如果 q u e r y ( l 0 , l − 1 ) + 1 + q u e r y ( r + 1 , r 0 ) ≠ q u e r y ( l 0 , r 0 ) query(l_0,l-1)+1+query(r+1,r_0)\ne query(l_0,r_0) query(l0,l−1)+1+query(r+1,r0)̸=query(l0,r0) 則區間 [ l , r ] [l,r] [l,r] 不能成為答案
- 否則區間 [ l , r ] [l,r] [l,r] 可以成為答案,直接加入答案
- 複雜度 O ( n log n ) O(n\log n) O(nlogn)
Code
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
#define p2 p << 1
#define p3 p << 1 | 1
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 2e5 + 5, M = N << 1, L = M << 2, LogN = 20;
int n, m, tm, tmp[M], fa[N][LogN], dep[N], ri[M], sum[L], add[L],
ansm, ans[N], pre0[L], suf0[L];
std::vector<int> itv[M];
struct node
{
int l, r;
} a[N];
void build(int l, int r, int p)
{
sum[p] = add[p] = 0;
pre0[p] = suf0[p] = r - l + 1;
if (l == r) return;
int mid = l + r >> 1;
build(l, mid, p2); build(mid + 1, r, p3);
}
void down(int p)
{
add[p2] += add[p]; add[p3] += add[p];
add[p] = 0;
}
void upt(int l, int r, int p)
{
int mid = l + r >> 1, lp0, rp0, ls0, rs0;
sum[p] = sum[p2] + sum[p3]
+ (mid - l + 1) * add[p2] + (r - mid) * add[p3];
lp0 = add[p2] ? 0 : pre0[p2];
rp0 = add[p3] ? 0 : pre0[p3];
ls0 = add[p2] ? 0 : suf0[p2];
rs0 = add[p3] ? 0 : suf0[p3];
pre0[p] = lp0 == mid - l + 1 ? lp0 + rp0 : lp0;
suf0[p] = rs0 == r - mid ? rs0 + ls0 : rs0;
}
void change(int l, int r, int s, int e, int v, int p)
{
if (l == s && r == e) return (void) (add[p] += v);
int mid = l + r >> 1;
down(p);
if (e <= mid) change(l, mid, s, e, v, p2);
else if (s >= mid + 1) change(mid + 1, r, s, e, v, p3);
else change(l, mid, s, mid, v, p2),
change(mid + 1, r, mid + 1, e, v, p3);
upt(l, r, p);
}
int ask(int l, int r, int s, int e, int p)
{
if (l == s && r == e) return sum[p] + (r - l + 1) * add[p];
int mid = l + r >> 1, res;
down(p);
if (e <= mid) res = ask(l, mid, s, e, p2);
else if (s >= mid + 1) res = ask(mid + 1, r, s, e, p3);
else res = ask(l, mid, s, mid, p2)
+ ask(mid + 1, r, mid + 1, e, p3);
return upt(l, r, p), res;
}
int askpre0(int l, int r, int s, int e, int p)
{
if (l == s && r == e) return add[p] ? 0 : pre0[p];
int mid = l + r >> 1, res;
down(p);
if (e <= mid) res = askpre0(l, mid, s, e, p2);
else if (s >= mid + 1) res = askpre0(mid + 1, r, s, e, p3);
else
{
int lp = askpre0(l, mid, s, mid, p2),
rp = askpre0(mid + 1, r, mid + 1, e, p3);
res = lp == mid - s + 1 ? lp + rp : lp;
}
return upt(l, r, p), res;
}
int asksuf0(int l, int r, int s, int e, int p)
{
if (l == s && r == e) return add[p] ? 0 : suf0[p];
int mid = l + r >> 1, res;
down(p);
if (e <= mid) res = asksuf0(l, mid, s, e, p2);
else if (s >= mid + 1) res = asksuf0(mid + 1, r, s, e, p3);
else
{
int ls = asksuf0(l, mid, s, mid, p2),
rs = asksuf0(mid + 1, r, mid + 1, e, p3);
res = rs == e - mid ? rs + ls : rs;
}
return upt(l, r, p), res;
}
int getans(int l, int r)
{
if (l > r) return 0;
if (!ri[l] || a[ri[l]].r > r) return 0;
int i, u = ri[l], st = u;
Rof (i, 17, 0)
if (fa[u][i] && a[fa[u][i]].r <= r)
u = fa[u][i];
return dep[st] - dep[u] + 1;
}
int main()
{
int i, j, k, sz;
n = read();
For (i, 1, n)
{
a[i].l = read(); a[i].r = read();
tmp[++tm] = a[i].l;
tmp[++tm] = a[i].r;
}
std::sort(tmp + 1, tmp + tm + 1);
m = std::unique(tmp + 1, tmp + tm + 1) - tmp - 1;
For (i, 1, n)
{
a[i].l = std::lower_bound(tmp + 1, tmp + m + 1, a[i].l) - tmp;
a[i].r = std::lower_bound(tmp + 1, tmp + m + 1, a[i].r) - tmp;
}
For (i, 1, n) itv[a[i].l].push_back(i);
For (i, 1, n) if (!ri[a[i].l] || a[i].r < a[ri[a[i].l]].r)
ri[a[i].l] = i;
Rof (i, m - 1, 1)
ri[i] = !ri[i] || !ri[i + 1] ? ri[i] + ri[i + 1] :
(a[ri[i]].r < a[ri[i + 1]].r ? ri[i] : ri[i + 1]);
Rof (i, m, 1)
{
int sz = itv[i].size();
For (j, 0, sz - 1)
{
int u = itv[i][j];
fa[u][0] = ri[a[u].r + 1];
dep[u] = dep[ri[a[u].r + 1]] + 1;
For (k, 0, 16)
fa[u][k + 1] = fa[fa[u][k]][k];
}
}
build(1, m, 1);
For (i, 1, n)
{
if (ask(1, m, a[i].l, a[i].r, 1)) continue;
int l = a[i].l - asksuf0(1, m, 1, a[i].l, 1) + 1,
r = a[i].r + askpre0(1, m, a[i].r, m, 1) - 1;
if (getans(l, r) != getans(l, a[i].l - 1)
+ getans(a[i].r + 1, r) + 1) continue;
ans[++ansm] = i;
change(1, m, a[i].l, a[i].r, 1, 1);
}
std::cout << ansm << std::endl;
For (i, 1, ansm) printf("%d ", ans[i]);
std::cout << std::endl;
return 0;
}