1 条题解

  • 1
    @ 2022-04-04 17:43:28
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n;
    long long ans;
    int t;
    struct node
    {
        int left,right;
        int c;
    } tree[4*40005*2];
    struct edge
    {
        int left,right,h;
    } a[40005];
    int p[2*40005];
    bool cmp(edge e1,edge e2)
    {
        return e1.h<e2.h;
    }
    //二分查找当前所要修改的离散化区间,即对应的矩形顶点的区间,
    //比如样例里,当处理第一个矩形时,修改的区间为(1,2),
    //即第一个矩形的两个顶点在p数组中对应的下标为1、2;
    int erfen(int l,int r,int x)
    {
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(p[mid]==x) return mid;
            else if(p[mid]>x) r=mid-1;
            else l=mid+1;
        }
        return 0;
    }
    void change(int now,int l,int r,int x)   //裸的区间修改
    {
        if(tree[now].right<l||tree[now].left>r) return;
        if(tree[now].left>=l&&tree[now].right<=r)
        {
            tree[now].c=x;
            return;
        }
        int mid=(tree[now].left+tree[now].right)/2;
        if(tree[now].c)
        {
            tree[now*2].c=tree[now].c;
            tree[now*2+1].c=tree[now].c;
            tree[now].c=0;
        }
        if(mid>=r)     change(now*2,l,r,x);
        else if(mid<=l) change(now*2+1,l,r,x);
        else
        {
            change(now*2,l,r,x);
            change(now*2+1,l,r,x);
        }
    }
    void built(int now,int l,int r)
    {
        tree[now].left=l;
        tree[now].right=r;
        tree[now].c=0;
        if(l==r-1) return;
        built(now*2,l,(l+r)/2);
        built(now*2+1,(l+r)/2,r);//*右界要包括mid,因为一个矩形所占的位置肯定大于一个点,如果不包括mid,会漏掉一些矩形;
    }
    void quest(int now)
    {
        if(tree[now].c)
        {
            ans+=(p[tree[now].right]-p[tree[now].left])*(long long)tree[now].c;//矩形面积
            return;
        }
        if(tree[now].right==tree[now].left+1) return;
        quest(now*2);
        quest(now*2+1);
    }
    int main()
    {
        scanf("%d",&n);//n个区间
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d%d",&a[i].left,&a[i].right,&a[i].h);
            p[++t]=a[i].left;
            p[++t]=a[i].right;
        }//离散化顶点
    
        sort(p+1,p+1+2*n);//每个区间2个点,所以是2n个点,将所有点从小到大排序
        sort(a+1,a+n+1,cmp);//按每个区间的高度从小到大排序
        built(1,1,n*2);//建树,每个叶子结点其实是p数组的一个下标
        for(int i=1; i<=n; i++)
        {
            int l=erfen(1,2*n,a[i].left);//l和下面的r都是p数组的下标
            int r=erfen(1,2*n,a[i].right);
            change(1,l,r,a[i].h);
        }
        quest(1);
        printf("%lld",ans);
    }
    

    这一题关键有\(4\)点:
    \(1\)、离散化
    为什么需要离散化?因为区间范围太大了,区间范围长度就是线段树叶子结点个数。
    没有办法建立一个这么大线段树。
    但是区间的个数是有限的,所以用区间的总端点数(区间数\(×2\))来建立一棵线段树
    最后需要来查找区间的时候,就去该离散化后的线段树上去查找。
    因为是先对\(p\)数组排序后再建立线段树的,所以\(a[i]\)位置小的自然\(p[i]\)的位置也小

    \(2\)、对区间按高度从小到大排序
    因为只有排过序,后面的高度比前面的更高,这样修改才不至于覆盖掉前面的内容。

    \(3\)、本题的\(tree[now].c\)相当于是\(lazy\)标记,因为就只查\(1\)次,所以查询时不需要做标记下传动作。

    \(4\)、 \(tree[now].c\)相当于\(lazy\)标记,其实他表示的是\(tree[now].left\)到
    \(tree[now].right\)这个区间的高
    那为什么有时候会是\(0?\)
    因为有时候这个区间并没有一个统一的高度,而是多个不同高度的矩形组合而成的
    所以就要继续向下搜索孩子区间,直到发现\(tree[now].c\)不为\(0\),
    此时这个区间高度确定了,此时直接拿区间长度\(×\)区间高度

  • 1

信息

ID
1122
难度
8
分类
线段树 点击显示
标签
递交数
9
已通过
1
通过率
11%
上传者