• 扫描线+线段树学习笔记


    如果仔细观察扫描仪工作就会发现,扫描仪扫描时是一条线从头到尾扫一遍成像。这个算法形象化表示也是如此。

    首先是扫描线板子题:矩形面积并。

    题意:在平面直角坐标系中,给出若干个矩形,求所有矩形的面积并。

    太长不看版:对于所有矩形的端点按照纵坐标排序,然后依次扫描矩形每加入一条线段覆盖,线段树查询所有区间中覆盖的长度即可。 

    详细来说,就是我们对每个矩形进行抽象化处理,把矩形的水平两条边单独拿出来,记录这条边的左右端点和高度。并且给这条边赋上一个特殊的值,为+1或-1,对于矩形下方的边赋+1,上方的边赋-1,表示扫描过程中进入和离开矩形。然后用一个线段树维护区间内的线段长度,再乘上对应高度就行。

    然后来一道需要稍稍构造一下的题:

    每个人都有一个能力值ai,而如果两个人之间的能力值差距过大,那么两个人就无法交流,然而每个人的沟通能力也是不同的,具体来讲,每个人只能接受能力值在[li,ri]内的人做他的队友,想让队伍里的人数尽可能的多,请你输出这个最多的人数。

    我们注意到,假设在队伍人数最多时,所有的人能接受的区间为[L,R],那么对每个人来说li <= L <= a,a <= R <= ri,所以我们可以把每个人看成一个矩形,矩形水平方向边为[li,ai],竖直方向的边为[ai,ri],问题就转化为找到一个点使得覆盖这个点矩形数目最多,那就直接扫描线,每次扫到一条边就区间+1或-1,维护区间最大值,就可以了。复杂度O(nlogn)。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<iostream>
    #include<ctime>
    #define B printf("Break
    ");
    #define A(x) cout << #x << " " << (x) << endl;
    #define ll long long
    using namespace std;
    int read()
    {
        int x = 0,f = 1;
        char c = getchar();
        while(c < '0' || c > '9') 
        {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9')
        {
            x = (x << 3) + (x << 1) + c - '0';
            c = getchar();
        }
        return f * x;
    }
    #define N 300010
    int ans;
    struct Rec
    {
        int l,r,h;
        int op;
        bool operator < (const Rec &x) const
        {
            if(h == x.h) return op > x.op;
            return h < x.h;
        }
    }rec[N << 1];
    #define ls x << 1,l,mid
    #define rs (x << 1 | 1),mid + 1,r
    #define mid ((l + r) >> 1)
    int tree[N << 2],lazy[N << 2];
    void add(int x,int l,int r,int k)
    {
        tree[x] += k;
        lazy[x] += k;
        return;
    }
    void push_down(int x,int l,int r)
    {
        if(lazy[x] == 0) return;
        add(ls,lazy[x]);
        add(rs,lazy[x]);
        lazy[x] = 0;
        return;
    }
    void modify(int x,int l,int r,int p,int q,int k)
    {
        if(p <= l && r <= q)
        {
            add(x,l,r,k);
            return;
        }
        push_down(x,l,r);
        if(p <= mid) modify(ls,p,q,k);
        if(q > mid) modify(rs,p,q,k);
        tree[x] = max(tree[x << 1],tree[x << 1 | 1]);
        return;
    }
    int cnt;
    void Add(int l,int a,int r)
    {
        rec[++cnt].l = l;
        rec[cnt].r = a;
        rec[cnt].h = a;
        rec[cnt].op = 1;
        rec[++cnt].l = l;
        rec[cnt].r = a;
        rec[cnt].h = r;
        rec[cnt].op = -1;
        return;
    }
    int main()
    {
        int n = read();
        for(int i = 1;i <= n;i++) 
        {
            int l = read(),a = read(),r = read();
            Add(l,a,r);
        }
        sort(rec + 1,rec + 1 + cnt);
        for(int i = 1;i <= cnt;i++)
        {
            int l = rec[i].l,r = rec[i].r;
            modify(1,1,300000,l,r,rec[i].op);
            ans = max(ans,tree[1]);
        }
        printf("%d
    ",ans);
    }
  • 相关阅读:
    Ocelot网关
    .Net Configuration配置优先级问题
    FilterContext/HttpContext 获取请求参数
    关于.Net的文件上传问题
    Notion+Zetero文献同步配置
    PyTorch训练模版
    marked ASP.NET 页面对象模型
    转:jQuery设计思想
    tryParse, try/catch(Parse), Convert比较
    CSS3 :nthchild()伪类选择器
  • 原文地址:https://www.cnblogs.com/lijilai-oi/p/11103766.html
Copyright © 2020-2023  润新知