• POJ


    POJ - 1177 扫描线

    这道题也算是一道扫描线的经典题目了。

    只不过这道题是算周长,非常有意思的一道题。我们已经知道了,一般求面积并,是如何求的,现在我们要把扫描线进行改造一下,使得能算周长。

    我们大致考虑一下图像上是如何实现的:

    这样一个图我们要如何求他的面积?

     

    我们把轮廓画出来

     

    我们把扫描线画出来

     

    我们发现

    从上到下我们竖直方向的长度,是每条线高度差*2*线段树的连续的段数目。

    从上到下我们水平方向的长度,是横线的长度现在这次总区间被覆盖的长度和上一次总区间被覆盖的长度之差的绝对值。

    这样我们就找到解决的办法,维护就非常容易了,本题范围比较小,因此不用离散化,直接区间建树,节点维护4个值,

    Len:区间内部被覆盖一次以上的长度

    S:区间内被完全覆盖的次数

    这个是常规操作。

    然后维护区间内部,连续区间(每个之间是隔离的)的个数

    然后两个lc,rc,代表区间左端点和右端点是否在连续区间内(合并区间的时候有用)

    这样就行了。

    然后考虑子节点往上pushup的情况,

    首先区间被完全填满,那么len等于区间长度,lc,rc,num都是1

    如果到叶节点,都是0

    否则,len,rc,lc,的长度由两个儿子节点提供,需要注意的是,num的情况是由两个儿子提供,如果左儿子的右边界和右儿子的左边界都是在连续的区间中,那么这个区间会被合成为1个区间,从而个数需要减1.

    最后常规的操作即可。

    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    const int N = 5007;
    const int X = 20007;
    const int inf = 1<<29;
    inline int L(int r){return r<<1;};
    inline int R(int r){return r<<1|1;};
    inline int MID(int l,int r){return (l+r)>>1;};
    struct Edge{
         int l,r;
         int h;
         int f;
    }line[N*2];
    struct node{
       int l,r,len,s,num;
       //num这个区间有多少不连续的线段
       bool lc,rc;//区间左右端点是否被覆盖
    }tree[X<<2];
    bool cmp(Edge a,Edge b)
    {
        return a.h<b.h;
    }
    void pushup(int root)
    {
        if (tree[root].s){
            tree[root].len=tree[root].r-tree[root].l+1;//没有离散化
            tree[root].rc=tree[root].lc=1;
            tree[root].num=1;
        }else if (tree[root].l == tree[root].r){
             tree[root].len=0;
             tree[root].lc=tree[root].rc=0;
             tree[root].num=0;
        }else{
             tree[root].len=tree[L(root)].len+tree[R(root)].len;
             tree[root].lc=tree[L(root)].lc;
             tree[root].rc=tree[R(root)].rc;
             tree[root].num=tree[L(root)].num+tree[R(root)].num-(tree[L(root)].rc && tree[R(root)].lc);
        }
    }
    void buildtree(int root,int l,int r){
       tree[root].l=l;
       tree[root].r=r;
       tree[root].s=tree[root].len=0;
       tree[root].lc = tree[root].rc = tree[root].num = 0;
       if (l==r){
         return ;
       }
       int mid = MID(l,r);
       buildtree(L(root),l,mid);
       buildtree(R(root),mid+1,r);
    }
    void update(int root,int ul,int ur,int v)
    {
        int l=tree[root].l;
        int r=tree[root].r;
        //cout<<root<<l<<" "<<r<<" "<<ul<<" "<<ur<<endl;
        if (ul==l && ur==r)
        {
            tree[root].s+=v;
            pushup(root);
            return;
        }
        int mid = MID(l,r);
        if (ur<=mid)update(L(root),ul,ur,v);
        else if(ul>mid)update(R(root),ul,ur,v);
        else{
            update(L(root),ul,mid,v);
            update(R(root),mid+1,ur,v);
        }
        pushup(root);
    }
    int main(){
      int n;
      while(scanf("%d",&n)!=EOF){
         int x1,x2,y1,y2,mx=-inf,mn=inf;
         int tot=0;
         for (int i=0;i<n;i++){
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            mx=max(mx,max(x1,x2));
            mn=min(mn,min(x1,x2));
            line[tot].l=x1;
            line[tot].r=x2;
            line[tot].h=y1;
            line[tot++].f=1;
            line[tot].l=x1;
            line[tot].r=x2;
            line[tot].h=y2;
            line[tot++].f=-1;
         }
         sort(line,line+tot,cmp);
         int ans=0;
         int last=0;
         buildtree(1,mn,mx-1);
        // cout<<"ss"<<endl;
         for (int i=0;i<tot;i++)
         {
           //  cout<<line[0].l<<" "<<line[0].r<<endl;
             update(1,line[i].l,line[i].r-1,line[i].f);
             ans+=abs(tree[1].len-last);
             ans+=(line[i+1].h-line[i].h)*2*tree[1].num;
             last=tree[1].len;
         }
        printf("%d
    ",ans);
      }
      return 0;
    }

    #include<iostream>#include<algorithm>#include<stdio.h>#include<string.h>usingnamespacestd; constint N = 5007; constint X = 20007; constint inf = 1<<29; inline int L(int r){return r<<1;}; inline int R(int r){return r<<1|1;}; inline int MID(int l,int r){return (l+r)>>1;}; struct Edge{ int l,r; int h; int f; }line[N*2]; struct node{ int l,r,len,s,num; //num这个区间有多少不连续的线段bool lc,rc;//区间左右端点是否被覆盖 }tree[X<<2]; bool cmp(Edge a,Edge b) { return a.h<b.h; } void pushup(int root) { if (tree[root].s){ tree[root].len=tree[root].r-tree[root].l+1;//没有离散化 tree[root].rc=tree[root].lc=1; tree[root].num=1; }elseif (tree[root].l == tree[root].r){ tree[root].len=0; tree[root].lc=tree[root].rc=0; tree[root].num=0; }else{ tree[root].len=tree[L(root)].len+tree[R(root)].len; tree[root].lc=tree[L(root)].lc; tree[root].rc=tree[R(root)].rc; tree[root].num=tree[L(root)].num+tree[R(root)].num-(tree[L(root)].rc && tree[R(root)].lc); } } void buildtree(int root,int l,int r){ tree[root].l=l; tree[root].r=r; tree[root].s=tree[root].len=0; tree[root].lc = tree[root].rc = tree[root].num = 0; if (l==r){ return ; } int mid = MID(l,r); buildtree(L(root),l,mid); buildtree(R(root),mid+1,r); } void update(int root,int ul,int ur,int v) { int l=tree[root].l; int r=tree[root].r; //cout<<root<<l<<" "<<r<<" "<<ul<<" "<<ur<<endl;if (ul==l && ur==r) { tree[root].s+=v; pushup(root); return; } int mid = MID(l,r); if (ur<=mid)update(L(root),ul,ur,v); elseif(ul>mid)update(R(root),ul,ur,v); else{ update(L(root),ul,mid,v); update(R(root),mid+1,ur,v); } pushup(root); } int main(){ int n; while(scanf("%d",&n)!=EOF){ int x1,x2,y1,y2,mx=-inf,mn=inf; int tot=0; for (int i=0;i<n;i++){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); mx=max(mx,max(x1,x2)); mn=min(mn,min(x1,x2)); line[tot].l=x1; line[tot].r=x2; line[tot].h=y1; line[tot++].f=1; line[tot].l=x1; line[tot].r=x2; line[tot].h=y2; line[tot++].f=-1; } sort(line,line+tot,cmp); int ans=0; int last=0; buildtree(1,mn,mx-1); // cout<<"ss"<<endl;for (int i=0;i<tot;i++) { // cout<<line[0].l<<" "<<line[0].r<<endl; update(1,line[i].l,line[i].r-1,line[i].f); ans+=abs(tree[1].len-last); ans+=(line[i+1].h-line[i].h)*2*tree[1].num; last=tree[1].len; } printf("%d ",ans); } return0; }

    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    【转载】C#使用Split函数根据特定分隔符分割字符串
    【转载】 Asp.Net安全之防止脚本入
    【转载】C#使用as关键字将对象转换为指定类型
    【转载】C#使用is关键字检查对象是否与给定类型兼容
    【转载】C#将字符串中字母全部转换为大写或者小写
    【转载】使用Response.WriteFile输出文件以及图片
    【转载】常见面试题:C#中String和string的区别分析
    【转载】Asp.Net中Cookie对象的作用以及常见属性
    【转载】C#指定文件夹下面的所有内容复制到目标文件夹下面
    【转载】Asp.Net中应用程序的事件响应次序
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/10360175.html
Copyright © 2020-2023  润新知