[BZOJ1178][Apio2009]CONVENTION會議中心(倍增 + 貪心 + 線段樹)
阿新 • • 發佈:2018-11-23
Address
Code
- 先離散化區間端點
- 預處理出對於每個區間 ,滿足 且 最小的區間
- 下文稱之為「 的後繼為 」
- 考慮一個小問題
- 查詢在包含於 的所有區間中,最多能選出多少個互不相交的區間
- 先找到包含於 且右端點最小的區間 (不存在則答案為 )
- 問題轉化為 至少跳多少次後繼之後右端點超過 或者不存在後繼
- 倍增 預處理後 查詢
- 考慮貪心地編號從小往大,考慮每個區間是否可以成為答案
- 設當前考慮區間
- 如果 記憶體在一點,已經被之前選出的區間覆蓋,則這個區間不能成為答案
- 否則設 為滿足 都沒有被覆蓋的最小的
- 為滿足 都沒有被覆蓋的最大的
- 設 表示包含於 的所有區間中最多選出多少個區間互不相交
- 如果 則區間 不能成為答案
- 否則區間 可以成為答案,直接加入答案
- 複雜度
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