zoukankan      html  css  js  c++  java
  • POJ 1177:线段树 离散化 扫描线

    计算畸形区域的周长

    比面积的扫描要麻烦些,原因就在不重叠区域的处理,同一段高度可能要重复叠加

    所以线段树的结点里要多维护三个东西:

    times:区间里不重叠的区间数

    比如说第一个区间是1~5,第二个是2~6,,第三个是9~10,那前两个可以合成1~6,和第三个独立,则这个整体的times为2

    为了维护times,我们需要lbd和rbd两个变量,分别作为区间左右端点是否被覆盖的标志

    有的博客里把这两个变量写成了bool型,这些其实不好,在运算时会带来麻烦,我们直接用int 0和1表示会好些。这样只有在左孩子的rbd*右孩子的lbd!=0的时候才表示两孩子连接时会多一个覆盖次数

    感觉扫描线的题目最关键的就是即使把更新后的影响传递上去

    还有一个比较关键的东西就是离散化的理解

    我的离散化是:把每一个x及其与下一个x之间的区间看作一个整体

    比如1 5 8三个点

    离散化后,1表示1~5,2表示5~8

    应该可以注意到,只需要离散n-1个点,因为最后一个点的右边是没有长度的

    所以当线段树中一个结点的表示区间是1~2,那这个区间的长度应该是1~8(1~5+5~8)

    具体看代码

    #include"cstdio"
    #include"queue"
    #include"cmath"
    #include"stack"
    #include"iostream"
    #include"algorithm"
    #include"cstring"
    #include"queue"
    #include"map"
    #include"set"
    #include"vector"
    #define ll long long
    #define mems(a,b) memset(a,b,sizeof(a))
    #define ls pos<<1
    #define rs pos<<1|1
    
    using namespace std;
    const int MAXN = 1e5+50;
    const int MAXQ = 10050;
    const int INF = 0x3f3f3f3f;
    int n,m;
    int x[MAXN];
    
    struct Line{
        int l,r,h,w;
        Line(){}
        Line(int a,int b,int c,int d):l(a),r(b),h(c),w(d){}
    }line[MAXN];
    
    bool cmp(Line a,Line b){
        return a.h<b.h;
    }
    
    struct Node{
        int l,r;
        int len;
        int cnt;
        int times;
        int w;
        int lbd,rbd;
    }node[MAXN<<2];
    
    void build(int l,int r,int pos){
        node[pos].l=l;
        node[pos].r=r;
        node[pos].cnt=node[pos].w=node[pos].times=0;
        node[pos].lbd=node[pos].rbd=0;
        node[pos].len=x[node[pos].r+1]-x[node[pos].l];
        if(l==r) return;
        int mid=(l+r)>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
    }
    
    void pushup(int pos){
        if(node[pos].w>0){
            node[pos].cnt=node[pos].len;
            node[pos].lbd=node[pos].rbd=node[pos].times=1;
        }
        else if(node[pos].l==node[pos].r){
            node[pos].cnt=0;
            node[pos].lbd=node[pos].rbd=node[pos].times=0;
        }
        else{
            node[pos].cnt=node[ls].cnt+node[rs].cnt;
            node[pos].lbd=node[ls].lbd;
            node[pos].rbd=node[rs].rbd;
            node[pos].times=node[ls].times+node[rs].times-node[rs].lbd*node[ls].rbd;
        }
    }
    
    int get_pos(int w){
        int low=0,high=m,mid,ans;
        while(low<=high){
            mid=(low+high)>>1;
            if(x[mid]==w) return mid;
            else if(x[mid]>w) high=mid-1;
            else low=mid+1;
        }
    }
    
    void update(int l,int r,int pos,int w){
        if(l<=node[pos].l&&node[pos].r<=r){
            node[pos].w+=w;
            pushup(pos);
            return;
        }
        int mid=(node[pos].l+node[pos].r)>>1;
        if(l<=mid) update(l,r,ls,w);
        if(r>mid) update(l,r,rs,w);
        pushup(pos);
    }
    
    int main(){
        //freopen("in.txt","r",stdin);
        while(~scanf("%d",&n)){
            for(int i=0;i<2*n;i+=2){
                int x1,y1,x2,y2;
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                line[i]=Line(x1,x2,y1,1);
                line[i+1]=Line(x1,x2,y2,-1);
                x[i]=x1;
                x[i+1]=x2;
            }
            sort(line,line+2*n,cmp);
            sort(x,x+2*n);
            m=0;
            for(int i=1;i<2*n;i++) if(x[i]!=x[i-1]) x[++m]=x[i];
            build(0,m-1,1);
            int ans=0;
            int pre=0;
            for(int i=0;i<2*n-1;i++){
                int l=get_pos(line[i].l);
                int r=get_pos(line[i].r)-1;
                update(l,r,1,line[i].w);
                ans+=2*node[1].times*(line[i+1].h-line[i].h);
                ans+=abs(node[1].cnt-pre);
                pre=node[1].cnt;
            }
            ans+=line[2*n-1].r-line[2*n-1].l;
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    SQL性能优化(不断总结)
    字符编码:区位/国标(gb2312、gbk)/机内码/ASCII/ANSI/Big5
    计算机中信息编码
    删除sybase一列报错:The 'select into' database option is not enabled for database.....
    常用Oracle函数(From OTN)
    常用正则
    剖析Windows的消息运行机制 (学习一)
    服务器响应码及解释
    了解注册表结构
    Windows消息大全收藏
  • 原文地址:https://www.cnblogs.com/luxiaoming/p/5158891.html
Copyright © 2011-2022 走看看