Problem
个互不相交或完全覆盖的矩形, 个点,每个点有一种颜色,求每个矩形覆盖的不同颜色.
Solution
重点在于矩形互不相交或完全覆盖.
所以可以看到,每一个矩形会有一个刚好囊括它的矩形,或者没有.
那么这样可以构成一颗森林.
在森林上进行set启发式合并,或者线段树合并就可以了.
构森林的时候我们有两种方式:
- 扫描线,线段树处理 轴,每次找到一个矩形之后判断其下边界是否合法,否则就倍增往其父亲走,直到合法.
- 标记永久化,对一段区间打标记,关键是如何撤回,其实很简单,就用其父亲的标记覆盖就好了.
分析一下线段树合并的时间复杂度,设势能函数表示总结点个数,那么总势能是 的.
考虑两颗线段树合并,时间复杂度可视为两颗线段树相同区间的点数,那么每走到一个相同点,时间复杂度加 ,然后势能减少一个,由于总势能是 。
所以最终合并的时间复杂度也是 的。
线段树合并
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define get getchar()
#define F(i, a, b) for (int i = a; i <= b; i ++)
#define mx(a, b) ((a) = (a) > (b) ? (a) : (b))
#define mem(a, b) memset(a, b, sizeof a)
#define Ls x << 1
#define Rs x << 1 | 1
#define Sp 2139062143
const int N = 5e5 + 10;
using namespace std;
int n, m, L, cntx, cnty, cntk, X[N], Y[N], K[N];
int tov[N], nex[N], las[N], tot, Ans[N]; bool vis[N];
struct Seg {
int A, B, C, D, num;
} d[N];
struct LSH {
int v, num, x;
} h[N];
int Yes, ans, cnt, fa[20][N], rt[N];
struct Segment_Tree {
int v, ans;
} tr[4 * N];
struct Doit {
int x, num, Q;
} D[N];
void Re(int &x) {
char c = get; x = 0; int t = 1;
for (; !isdigit(c); c = get) t = (c == '-' ? - 1 : t);
for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = get); x *= t;
}
void Wr(int x) {
if (x < 0) { putchar('-'); x = - x; }
if (x > 9) Wr(x / 10);
putchar(x % 10 + '0');
}
bool cmp ( LSH x, LSH y) {
return x.v < y.v;
}
void Init() {
F(i, 1, n)
h[++ L] = {d[i].A, i, 0}, h[++ L] = {d[i].C, i, 1};
F(i, 1, m)
h[++ L] = {X[i], n + i, 0};
sort(h + 1, h + L + 1, cmp);
h[0].v = h[1].v - 1;
F(i, 1, L) {
cntx += (h[i].v != h[i - 1].v);
if (h[i].num <= n) {
if (h[i].x == 0)
d[h[i].num].A = cntx;
else
d[h[i].num].C = cntx;
}
else
X[h[i].num - n] = cntx;
}
L = 0;
F(i, 1, n)
h[++ L] = {d[i].B, i, 0}, h[++ L] = {d[i].D, i, 1};
F(i, 1, m)
h[++ L] = {Y[i], n + i, 0};
sort(h + 1, h + L + 1, cmp);
h[0].v = h[1].v - 1;
F(i, 1, L) {
cnty += (h[i].v != h[i - 1].v);
if (h[i].num <= n) {
if (h[i].x == 0)
d[h[i].num].B = cnty;
else
d[h[i].num].D = cnty;
}
else
Y[h[i].num - n] = cnty;
}
L = 0;
F(i, 1, m)
h[++ L] = {K[i], i};
sort(h + 1, h + L + 1, cmp);
h[0].v = h[1].v - 1;
F(i, 1, L) {
cntk += (h[i].v != h[i - 1].v);
K[h[i].num] = cntk;
}
}
void ReadData() {
freopen("plahte.in", "r", stdin);
freopen("plahte.out", "w", stdout);
Re(n), Re(m);
F(i, 1, n)
Re(d[i].A), Re(d[i].B), Re(d[i].C), Re(d[i].D), d[i].num = i;
F(i, 1, m)
Re(X[i]), Re(Y[i]), Re(K[i]);
}
void Find(int x, int st, int en, int l, int r) {
if (l <= st && en <= r) {
if (tr[x].v < Yes) {
Yes = tr[x].v;
ans = tr[x].ans;
}
return;
}
int m = st + en >> 1;
if (m >= l) Find(Ls, st, m, l, r);
if (m < r) Find(Rs, m + 1, en, l, r);
}
void Modify(int x, int st, int en, int p, int q) {
if (st == en) {
if (tr[x].v == Sp)
tr[x].v = st, tr[x].ans = q;
else
tr[x].v = tr[x].ans = Sp;
return;
}
int m = st + en >> 1;
if (m >= p) Modify(Ls, st, m, p, q); else Modify(Rs, m + 1, en, p, q);
tr[x].ans = (tr[Ls].v < tr[Rs].v) ? tr[Ls].ans : tr[Rs].ans;
tr[x].v = min(tr[Ls].v, tr[Rs].v);
}
bool CMP(Doit x, Doit y) {
return x.x < y.x;
}
bool CMQ(Doit x, Doit y) {
return x.x < y.x || x.x == y.x && x.Q > y.Q;
}
struct Ans_Seg {
int v, l, r;
} Tr[4 * N];
void Get(int &x, int st, int en, int p) {
if (!x) Tr[x = ++ cnt] = {0, 0, 0};
if (st == en) { Tr[x].v = 1; return; }
int m = st + en >> 1;
if (m >= p) Get(Tr[x].l, st, m, p); else Get(Tr[x].r, m + 1, en, p);
Tr[x].v = Tr[Tr[x].l].v + Tr[Tr[x].r].v;
}
void GetTree() {
L = 0;
F(i, 1, n)
D[++ L].x = d[i].A, D[L].num = i, D[L].Q = - 1,
D[++ L].x = d[i].C, D[L].num = i, D[L].Q = 1;
sort(D + 1, D + L + 1, CMP);
mem(tr, 127);
F(i, 1, n) fa[0][i] = i;
F(i, 1, L) {
int num = D[i].num;
if (D[i].Q == - 1) {
ans = 0, Yes = 1e9, Find(1, 1, cnty, d[num].D + 1, cnty);
if (ans) {
for (int j = 18; j >= 0; j --)
if (fa[j][ans] && d[fa[j][ans]].B > d[num].B)
ans = fa[j][ans];
if (d[ans].B > d[num].B)
ans = fa[0][ans];
if (d[ans].B < d[num].B) {
fa[0][num] = ans;
F(j, 1, 18)
fa[j][num] = fa[j - 1][fa[j - 1][num]];
}
}
}
Modify(1, 1, cnty, d[D[i].num].D, D[i].num);
}
mem(tr, 127), L = 0;
F(i, 1, n)
D[++ L].x = d[i].A, D[L].num = i, D[L].Q = 1,
D[++ L].x = d[i].C, D[L].num = i, D[L].Q = - 1;
F(i, 1, m)
D[++ L].x = X[i], D[L].num = i + n, D[L].Q = 0;
sort(D + 1, D + L + 1, CMQ);
F(i, 1, L) {
if (D[i].num > n) {
int num = D[i].num - n;
ans = 0, Yes = 1e9, Find(1, 1, cnty, Y[num], cnty);
if (ans) {
for (int j = 18; j >= 0; j --)
if (fa[j][ans] && d[fa[j][ans]].B > Y[num])
ans = fa[j][ans];
if (d[ans].B > Y[num])
ans = fa[0][ans];
if (d[ans].B <= Y[num])
Get(rt[ans], 1, cntk, K[num]);
}
}
else
Modify(1, 1, cnty, d[D[i].num].D, D[i].num);
}
}
void link(int x, int y) {
tov[++ tot] = y, nex[tot] = las[x], las[x] = tot;
}
int Merge(int x, int y, int l, int r, int k) {
if (!x || !y) return x + y;
if (l == r) {
Tr[x].v = min(Tr[x].v + Tr[y].v, 1);
return x;
}
int m = l + r >> 1;
Tr[x].l = Merge(Tr[x].l, Tr[y].l, l, m, k);
Tr[x].r = Merge(Tr[x].r, Tr[y].r, m + 1, r, k);
Tr[x].v = Tr[Tr[x].l].v + Tr[Tr[x].r].v;
return x;
}
void Go(int k) {
vis[k] = 1;
for (int x = las[k]; x; x = nex[x])
if (!vis[tov[x]]) {
Go(tov[x]);
rt[k] = Merge(rt[k], rt[tov[x]], 1, cntk, k);
}
Ans[k] = Tr[rt[k]].v;
}
void DFS() {
F(i, 1, n)
if (fa[0][i] ^ i) link(fa[0][i], i);
F(i, 1, n)
if (fa[0][i] == i)
Go(i);
F(i, 1, n)
Wr(Ans[i]), putchar('\n');
}
int main() {
ReadData();
Init();
GetTree();
DFS();
}
Set启发式合并
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <set>
#define lowbit(x) ((x) & (-x))
#define get getchar()
#define F(i, a, b) for (int i = a; i <= b; i ++)
#define mx(a, b) ((a) = (a) > (b) ? (a) : (b))
const int N = 5e5 + 10, M = 5e5 + 10;
using namespace std;
int n, m, L, cntx, cnty, cntk, X[M], Y[M], K[M];
struct Seg {
int A, B, C, D, num;
} d[N];
struct LSH {
int v, num, x;
} h[N];
void Re(int &x) {
char c = get; x = 0; int t = 1;
for (; !isdigit(c); c = get) t = (c == '-' ? - 1 : t);
for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = get); x *= t;
}
void Wr(int x) {
if (x < 0) { putchar('-'); x = - x; }
if (x > 9) Wr(x / 10);
putchar(x % 10 + '0');
}
bool cmp ( LSH x, LSH y) {
return x.v < y.v;
}
void Init() {
F(i, 1, n)
h[++ L] = {d[i].A, i, 0}, h[++ L] = {d[i].C, i, 1};
F(i, 1, m)
h[++ L] = {X[i], n + i, 0};
sort(h + 1, h + L + 1, cmp);
h[0].v = h[1].v - 1;
F(i, 1, L) {
cntx += (h[i].v != h[i - 1].v);
if (h[i].num <= n) {
if (h[i].x == 0)
d[h[i].num].A = cntx;
else
d[h[i].num].C = cntx;
}
else
X[h[i].num - n] = cntx;
}
L = 0;
F(i, 1, n)
h[++ L] = {d[i].B, i, 0}, h[++ L] = {d[i].D, i, 1};
F(i, 1, m)
h[++ L] = {Y[i], n + i, 0};
sort(h + 1, h + L + 1, cmp);
h[0].v = h[1].v - 1;
F(i, 1, L) {
cnty += (h[i].v != h[i - 1].v);
if (h[i].num <= n) {
if (h[i].x == 0)
d[h[i].num].B = cnty;
else
d[h[i].num].D = cnty;
}
else
Y[h[i].num - n] = cnty;
}
L = 0;
F(i, 1, m)
h[++ L] = {K[i], i};
sort(h + 1, h + L + 1, cmp);
h[0].v = h[1].v - 1;
F(i, 1, L) {
cntk += (h[i].v != h[i - 1].v);
K[h[i].num] = cntk;
}
}
void ReadData() {
freopen("data.in", "r", stdin);
freopen("plahte.out", "w", stdout);
Re(n), Re(m);
F(i, 1, n)
Re(d[i].A), Re(d[i].B), Re(d[i].C), Re(d[i].D), d[i].num = i;
F(i, 1, m)
Re(X[i]), Re(Y[i]), Re(K[i]);
}
int Yes, ans;
struct Segment_Tree {
int v, ans;
} tr[4 * N];
#define mem(a, b) memset(a, b, sizeof a)
#define Ls x << 1
#define Rs x << 1 | 1
#define Sp 2139062143
void Find(int x, int st, int en, int l, int r) {
if (l <= st && en <= r) {
if (tr[x].v < Yes) {
Yes = tr[x].v;
ans = tr[x].ans;
}
return;
}
int m = st + en >> 1;
if (m >= l) Find(Ls, st, m, l, r);
if (m < r) Find(Rs, m + 1, en, l, r);
}
void Modify(int x, int st, int en, int p, int q) {
if (st == en) {
if (tr[x].v == Sp)
tr[x].v = st, tr[x].ans = q;
else
tr[x].v = tr[x].ans = Sp;
return;
}
int m = st + en >> 1;
if (m >= p) Modify(Ls, st, m, p, q); else Modify(Rs, m + 1, en, p, q);
tr[x].ans = (tr[Ls].v < tr[Rs].v) ? tr[Ls].ans : tr[Rs].ans;
tr[x].v = min(tr[Ls].v, tr[Rs].v);
}
struct Doit {
int x, num, Q;
} D[N];
bool CMP(Doit x, Doit y) {
return x.x < y.x;
}
bool CMQ(Doit x, Doit y) {
return x.x < y.x || x.x == y.x && x.Q > y.Q;
}
int fa[20][N];
set <int> Set[N];
void GetTree() {
L = 0;
F(i, 1, n)
D[++ L].x = d[i].A, D[L].num = i, D[L].Q = - 1,
D[++ L].x = d[i].C, D[L].num = i, D[L].Q = 1;
sort(D + 1, D + L + 1, CMP);
mem(tr, 127);
F(i, 1, n) fa[0][i] = i;
F(i, 1, L) {
int num = D[i].num;
if (D[i].Q == - 1) {
ans = 0, Yes = 1e9, Find(1, 1, cnty, d[num].D + 1, cnty);
if (ans) {
for (int j = 18; j >= 0; j --)
if (fa[j][ans] && d[fa[j][ans]].B > d[num].B)
ans = fa[j][ans];
if (d[ans].B > d[num].B)
ans = fa[0][ans];
if (d[ans].B < d[num].B) {
fa[0][num] = ans;
F(j, 1, 18)
fa[j][num] = fa[j - 1][fa[j - 1][num]];
}
}
}
Modify(1, 1, cnty, d[D[i].num].D, D[i].num);
}
mem(tr, 127), L = 0;
F(i, 1, n)
D[++ L].x = d[i].A, D[L].num = i, D[L].Q = 1,
D[++ L].x = d[i].C, D[L].num = i, D[L].Q = - 1;
F(i, 1, m)
D[++ L].x = X[i], D[L].num = i + n, D[L].Q = 0;
sort(D + 1, D + L + 1, CMQ);
F(i, 1, L) {
if (D[i].num > n) {
int num = D[i].num - n;
ans = 0, Yes = 1e9, Find(1, 1, cnty, Y[num], cnty);
if (ans) {
for (int j = 18; j >= 0; j --)
if (fa[j][ans] && d[fa[j][ans]].B > Y[num])
ans = fa[j][ans];
if (d[ans].B > Y[num])
ans = fa[0][ans];
if (d[ans].B <= Y[num])
Set[ans].insert(K[num]);
}
}
else
Modify(1, 1, cnty, d[D[i].num].D, D[i].num);
}
}
int tov[N], nex[N], las[N], tot, P[N], Ans[N];
bool vis[N];
void link(int x, int y) {
tov[++ tot] = y, nex[tot] = las[x], las[x] = tot;
}
void Go(int k) {
vis[k] = 1;
for (int x = las[k]; x; x = nex[x]) {
if (vis[tov[x]]) continue;
Go(tov[x]);
if (Set[P[k]].size() > Set[P[tov[x]]].size())
Set[P[k]].insert(Set[P[tov[x]]].begin(), Set[P[tov[x]]].end());
else
Set[P[tov[x]]].insert(Set[P[k]].begin(), Set[P[k]].end()), P[k] = P[tov[x]];
}
Ans[k] = Set[P[k]].size();
}
void DFS() {
F(i, 1, n)
if (fa[0][i] ^ i) link(fa[0][i], i);
F(i, 1, n)
P[i] = i;
F(i, 1, n)
if (fa[0][i] == i)
Go(i);
F(i, 1, n)
Wr(Ans[i]), putchar('\n');
}
int main() {
ReadData();
Init();
GetTree();
DFS();
}