[jzoj]5800. 2018.08.11【2018提高组】模拟A组 被单(线段树合并或set合并+扫描线)

Problem

  • n n 个互不相交或完全覆盖的矩形,m个点,每个点有一种颜色,求每个矩形覆盖的不同颜色.

  • n,m80000 n , m ≤ 80000

Solution

  • 重点在于矩形互不相交或完全覆盖.

  • 所以可以看到,每一个矩形会有一个刚好囊括它的矩形,或者没有.

  • 那么这样可以构成一颗森林.

  • 在森林上进行set启发式合并,或者线段树合并就可以了.

  • 构森林的时候我们有两种方式:

    • 扫描线,线段树处理 y y 轴,每次找到一个矩形之后判断其下边界是否合法,否则就倍增往其父亲走,直到合法.
    • 标记永久化,对一段区间打标记,关键是如何撤回,其实很简单,就用其父亲的标记覆盖就好了.
  • 分析一下线段树合并的时间复杂度,设势能函数表示总结点个数,那么总势能是mlog2n的.

  • 考虑两颗线段树合并,时间复杂度可视为两颗线段树相同区间的点数,那么每走到一个相同点,时间复杂度加 O(1) O ( 1 ) ,然后势能减少一个,由于总势能是 mlog2n m l o g 2 n

  • 所以最终合并的时间复杂度也是 O(mlog2n) O ( m l o g 2 n ) 的。

线段树合并
#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();
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值