• poj 2528 Mayor's posters 线段树 || 并查集 离线处理


    题目链接

    题意

    用不同颜色的线段覆盖数轴,问最终数轴上有多少种颜色?

    注:只有最上面的线段能够被看到;即,如果有一条线段被其他的线段给完全覆盖住,则这个颜色是看不到的。

    法一:线段树

    按题意按顺序模拟即可。

    法二:线段树+离线

    将整个过程倒过来看待,如果要加进去的线段所在的区域已经完全被覆盖,那么这条线段就没有贡献,否则就有(1)的贡献。

    法三:并查集+离线

    离线处理思想同上。

    (fa[ ])数组记录某个元素左边距其最近的没有被覆盖的点的坐标。那么对于当前覆盖的线段([l,r]),只要(find(r)lt l),就意味着当前这一段已经完全被覆盖,所以贡献为(0).

    并查集的思想类似BZOJ 3211 花神游历各国

    注意点

    这道题的坑点在于:离散化

    如果普通地进行离散化,考虑

    3
    1 10
    1 4
    6 10
    

    会被离散化成

    3
    1 4
    1 2
    3 4
    

    本来有三种颜色,处理过之后就只有两种颜色了。

    问题在于:顺序的连续并不代表位置的连续。

    处理时在中间插入额外的点即可。

    Code

    Ver. 1

    #include <stdio.h>
    #include <algorithm>
    #include <string.h>
    #define lson rt<<1
    #define rson rt<<1|1
    #define maxn 100010
    using namespace std;
    typedef long long LL;
    int a[maxn], l[maxn], r[maxn], b[maxn], ans;
    bool vis[maxn];
    struct tree { int l, r, c, flag; }tr[maxn*4];
    void build(int rt, int l, int r) {
        tr[rt].l = l, tr[rt].r = r; tr[rt].flag = tr[rt].c = 0;
        if (l==r) return;
        int mid = l+r >> 1;
        build(lson, l, mid), build(rson, mid+1, r);
    }
    void push_down(int rt) {
        if (tr[rt].flag) {
            tr[lson].flag = tr[rson].flag
                = tr[lson].c = tr[rson].c = tr[rt].flag;
            tr[rt].flag = 0;
        }
    }
    void push_up(int rt) {
        tr[rt].c = tr[lson].c == tr[rson].c ? tr[lson].c : 0;
    }
    void modify(int rt, int l, int r, int c) {
        if (tr[rt].l == l && tr[rt].r == r) {
            tr[rt].c = tr[rt].flag = c;
            return;
        }
        push_down(rt);
        int mid = tr[rt].l + tr[rt].r >> 1;
        if (r <= mid) modify(lson, l, r, c);
        else if (l > mid) modify(rson, l, r, c);
        else modify(lson, l, mid, c), modify(rson, mid+1, r, c);
        push_up(rt);
    }
    void query(int rt) {
        if (tr[rt].l == tr[rt].r || tr[rt].c) {
            if (!vis[tr[rt].c] && tr[rt].c) ++ans, vis[tr[rt].c] = true;
            return;
        }
        push_down(rt);
        query(lson); query(rson);
    }
    void work() {
        int n;
        scanf("%d", &n);
        int tot=0;
        for (int i = 1; i <= n; ++i) {
            scanf("%d%d", &l[i], &r[i]);
            a[++tot] = l[i], a[++tot] = r[i];
        }
        sort(a+1,a+tot+1);
        tot = unique(a+1,a+tot+1)-a-1;
    
        b[1] = a[1]; int cnt = 1;
        for (int i = 2; i <= tot; ++i) {
            if (a[i]-a[i-1] == 1) b[++cnt] = a[i];
            else b[++cnt] = a[i-1] + 1, b[++cnt] = a[i];
        }
    
        build(1,1,cnt);
        for (int i = 1; i <= n; ++i) {
            int pl = lower_bound(b+1, b+1+cnt, l[i]) - b,
                pr = lower_bound(b+1, b+1+cnt, r[i]) - b;
            modify(1, pl, pr, i);
        }
    
        ans = 0; memset(vis, 0, sizeof(vis));
        query(1);
        printf("%d
    ", ans);
    }
    int main() {
        int T;
        scanf("%d", &T);
        while (T--) work();
        return 0;
    }
    

    Ver. 2

    #include <stdio.h>
    #include <algorithm>
    #include <map>
    #define lson rt<<1
    #define rson rt<<1|1
    #define maxn 100010
    using namespace std;
    typedef long long LL;
    int a[maxn], l[maxn], r[maxn], b[maxn];
    struct tree { int l, r; bool cov, flag; }tr[maxn*4];
    map<int,int> mp;
    void build(int rt, int l, int r) {
        tr[rt].l = l, tr[rt].r = r; tr[rt].cov = 0; tr[rt].flag = 0;
        if (l==r) return;
        int mid = l+r >> 1;
        build(lson, l, mid), build(rson, mid+1, r);
    }
    void push_down(int rt) {
        if (tr[rt].flag) {
            tr[lson].cov = tr[rson].cov = tr[lson].flag = tr[rson].flag = 1;
            tr[rt].flag = 0;
        }
    }
    void push_up(int rt) {
        tr[rt].cov = tr[lson].cov && tr[rson].cov;
    }
    bool insert(int rt, int l, int r) {
        if (tr[rt].l==l && tr[rt].r==r) {
            if (tr[rt].cov) return true;
            tr[rt].cov = tr[rt].flag = true;
            return false;
        }
        push_down(rt);
        int mid = tr[rt].l + tr[rt].r >> 1;
        bool ret;
        if (r <= mid) ret = insert(lson, l, r);
        else if (l > mid) ret = insert(rson, l, r);
        else {
            //    注意!这里不能直接写成 ret = insert(lson, l, mid) & ans2 = insert(rson, mid+1, r);
            //    因为根据短路原理,如果前面的为假,后面的就直接不做了!
            bool ans1 = insert(lson, l, mid), ans2 = insert(rson, mid+1, r);
            ret = ans1&ans2;
        }
        push_up(rt);
        return ret;
    }
    void work() {
        int n;
        scanf("%d", &n);
        int tot=0;
        for (int i = 0; i < n; ++i) {
            scanf("%d%d", &l[i], &r[i]);
            a[++tot] = l[i], a[++tot] = r[i];
        }
        sort(a+1,a+tot+1);
        tot = unique(a+1,a+tot+1)-a-1;
    
        b[1] = a[1]; int cnt = 1;
        for (int i = 2; i <= tot; ++i) {
            if (a[i]-a[i-1] == 1) b[++cnt] = a[i];
            else b[++cnt] = a[i-1] + 1, b[++cnt] = a[i];
        }
    
        build(1,1,cnt);
        int ans=0;
        for (int i = n-1; i >= 0; --i) {
            int pl = lower_bound(b+1, b+1+cnt, l[i]) - b,
                pr = lower_bound(b+1, b+1+cnt, r[i]) - b;
            if (!insert(1, pl, pr)) ++ans;
        }
        printf("%d
    ", ans);
    }
    int main() {
        int T;
        scanf("%d", &T);
        while (T--) work();
        return 0;
    }
    

    Ver. 3

    #include <stdio.h>
    #include <algorithm>
    #include <map>
    #define maxn 100010
    using namespace std;
    typedef long long LL;
    int a[maxn], l[maxn], r[maxn], fa[maxn], b[maxn];
    int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
    map<int,int> mp;
    void work() {
        int n;
        scanf("%d", &n);
        int tot=0;
        for (int i = 0; i < n; ++i) {
            scanf("%d%d", &l[i], &r[i]);
            a[++tot] = l[i], a[++tot] = r[i];
        }
        sort(a+1,a+tot+1);
        tot = unique(a+1,a+tot+1)-a-1;
    
        b[1] = a[1]; int cnt = 1;
        for (int i = 2; i <= tot; ++i) {
            if (a[i]-a[i-1] == 1) b[++cnt] = a[i];
            else b[++cnt] = a[i-1] + 1, b[++cnt] = a[i];
        }
        for (int i=0; i<=cnt; ++i) fa[i] = i;
    
        int ans=0;
        for (int i = n-1; i >= 0; --i) {
            int pl = lower_bound(b+1, b+1+cnt, l[i]) - b,
                pr = lower_bound(b+1, b+1+cnt, r[i]) - b;
            if (find(pr)<pl) continue;
            ++ans;
            for (int j = find(pr); j >= pl; j = find(j-1)) {
                fa[find(j)] = find(pl-1);
            }
        }
        printf("%d
    ", ans);
    }
    int main() {
        int T;
        scanf("%d", &T);
        while (T--) work();
        return 0;
    }
    
  • 相关阅读:
    02 . Vue入门基础之条件渲染,列表渲染,事件处理器,表单控件绑定
    iptables防火墙简介,原理,规则编写,做网络防火墙,常见案例
    Go之发送钉钉和邮箱
    Jumpserver简介,部署及使用
    01 . Go语言实现SSH远程终端及WebSocket
    KVM简介,安装及常见使用,维护详解
    05 . Gin+Vue开发一个线上外卖应用(Session集成及修改用户头像到Fastdfs)
    04 . Gin+Vue开发一个线上外卖应用(用户名密码和图形验证码)
    03 . Gin+Vue开发一个线上外卖应用(用户数据创建,插入,跨域处理)
    02 . Go之Gin+Vue开发一个线上外卖应用(集成第三方发送短信和xorm生成存储数据库表)
  • 原文地址:https://www.cnblogs.com/kkkkahlua/p/7795493.html
Copyright © 2020-2023  润新知