POJ 1177 Picture(线段树:扫描线求轮廓周长)

Posted Yeader

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1177 Picture(线段树:扫描线求轮廓周长)相关的知识,希望对你有一定的参考价值。

题目链接:http://poj.org/problem?id=1177

题目大意:若干个矩形,求这些矩形重叠形成的图形的轮廓周长。

解题思路:这里引用一下大牛的思路:kuangbin

总体思路:

1.沿X轴离散化建树

2.按Y值从小到大排序平行与X轴的边,然后顺序处理

    如果遇到矩形下面那条边则插入到线段树中,遇到矩形上面的边则将相应的边删除掉

    根据线段树当前的状态统计长度

 

第二点是本题的核心思想,偶再举个例:

 


  第一次求出的部分很好理解.

  第二次求出的为什么会少了中间那部分.那是因为插入的新线段覆盖了第一条,此时线段树返回的长度是新的那一条的长度,将这个值再减去上次的就少了中间那部分

  第三次因为是矩形的上边,所以要删除在那条长的线段.此时的线段树返回的则是第一次的长度,将此值减去第二次返回值,再取其负值就是红色X轴那部分了

  最后那条X轴的,再补上就行了。

我写的稍微有点不同,不过大概也就是这个思路了。总结一下就是矩形下位边cnt+1,上位边cnt-1,求tree[1].sum,这些步骤跟求矩形面积并是一样的。

然后按照扫描线从小到大一次跟新,ans+=abs(上一次的测度-更新后的测度)。

然后就按x,y方向扫描线各求一遍,加在一起就是总的周长。(好像还是有点问题,就是重边会出错,不会改啊!!!算了,等以后变强了再来改0 0)

这题我没有离散化,因为数据不是很大也没有小数所以就懒得写了。。。

代码:

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<vector>
  7 #include<queue>
  8 #include<set>
  9 #include<map>
 10 #include<stack>
 11 #include<string>
 12 #define LC(a) (a<<1)
 13 #define RC(a) (a<<1|1)
 14 #define MID(a,b) ((a+b)>>1)
 15 using namespace std;
 16 typedef long long LL;
 17 const int INF=0x3f3f3f3f;
 18 const int N=1e4+5;
 19 
 20 struct Node{
 21     int l,r,cnt,sum;//sum为测度 
 22 }tree[N*2*4]; 
 23 
 24 struct node{
 25     int l,r,h,flag;
 26     node(){}
 27     node(double a,double b,double c,double d){
 28         l=a;r=b;h=c;flag=d;
 29     }
 30 }a[N],b[N];
 31 
 32 bool cmp(node a,node b){
 33     return a.h<b.h;
 34 }
 35 //因为每条线段对应删除的线段是严格出现的,不需要Lazy也就不需要pushdown()
 36 void pushup(int p) {
 37     if(tree[p].cnt>0)
 38         tree[p].sum=tree[p].r-tree[p].l+1;
 39     else if(tree[p].l==tree[p].r)
 40         tree[p].sum=0;
 41     else
 42         tree[p].sum=tree[LC(p)].sum+tree[RC(p)].sum;
 43 }
 44 
 45 void build(int p,int l,int r){
 46     tree[p].l=l;
 47     tree[p].r=r;
 48     if(l==r){
 49         tree[p].cnt=tree[p].sum=0;
 50         return;
 51     }
 52     build(LC(p),l,MID(l,r));
 53     build(RC(p),MID(l,r)+1,r);
 54     pushup(p);
 55 }
 56 
 57 void update(int p,int l,int r,int cnt){
 58     if(l>tree[p].r||r<tree[p].l)
 59         return;
 60     if(l<=tree[p].l&&r>=tree[p].r&&tree[p].cnt!=-1){
 61         tree[p].cnt+=cnt;
 62         pushup(p);
 63         return;
 64     }
 65     update(LC(p),l,r,cnt);
 66     update(RC(p),l,r,cnt);
 67     pushup(p);
 68 }
 69 
 70 int main(){
 71     int n;
 72     while(~scanf("%d",&n)){
 73         int m1=0,m2=1;
 74         for(int i=1;i<=n;i++){
 75             int x1,x2,y1,y2;
 76             scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
 77             x1+=N,x2+=N,y1+=N,y2+=N;//防止x,y出现负数 
 78             a[++m1]=node(x1,x2,y1,1);
 79             b[m1]=node(y1,y2,x1,1);
 80             a[++m1]=node(x1,x2,y2,-1);
 81             b[m1]=node(y1,y2,x2,-1);
 82         }
 83         sort(a+1,a+1+m1,cmp);
 84         sort(b+1,b+1+m1,cmp);
 85         //自下往上扫描一遍 
 86         build(1,1,2*N-1);
 87         int ans=0;
 88         for(int i=1;i<=m1;i++){
 89             int last=tree[1].sum;
 90             int l=a[i].l;
 91             int r=a[i].r-1;
 92             update(1,l,r,a[i].flag);
 93             ans+=abs(tree[1].sum-last);
 94         }
 95         //自左往右扫描一遍
 96         build(1,1,2*N-1);
 97         for(int i=1;i<=m1;i++){
 98             int last=tree[1].sum;
 99             int l=b[i].l;
100             int r=b[i].r-1;
101             update(1,l,r,b[i].flag);
102             ans+=abs(tree[1].sum-last);
103         }
104         printf("%d\\n",ans);    
105     }
106     return 0;
107 }

 

以上是关于POJ 1177 Picture(线段树:扫描线求轮廓周长)的主要内容,如果未能解决你的问题,请参考以下文章

Picture POJ - 1177 线段树+离散化+扫描线 求交叉图像周长

Picture POJ - 1177(扫描线 + 线段树)

HDOJ1828&&POJ1177Picture(线段树,扫描线)

poj 1177 Picture(线段树周长并)

整理线段树30题

POJ 1177:线段树 离散化 扫描线