线段树学习之:用线段数统计矩形的周长hdu(1828)

    学习如何用线段树来统计矩形的并面积后,接下来我学习一下如何用线段树来统计矩形周长的并!尽管其基本思路跟统计矩形的面积差不多,但估计是因为没有完全明白线段树的思想,我还是没有想出如何用线段树统计线段树的面积!

   在学习的过程中参考了以下两个博客的代码,最终以博客二的代码作为研究对象!

博客一:http://www.notonlysuccess.com/index.php/divide-tree/

博客二:http://hi.baidu.com/lw0090s/item/159f6ad6cab61b9c260ae731

   个人觉得博客二的代码更适合于像我这样的菜鸟!更容易理解!把代码贴出来!(注代码来源于博客二,不是本人写出来的)

 
 
  1. #include<iostream> 
  2. #include<algorithm> 
  3. #include<stdio.h> 
  4. using namespace std; 
  5. struct Line 
  6.     int x,y1,y2; 
  7.     int flag; 
  8. } line[5005*2]; 
  9. int y[5005*2]; 
  10. struct tree 
  11.     int lines,len,l,r,c,lb,rb; //lb表示线段左边端点是否被覆盖为0,1,rb同理右边 
  12. //lines表示当前线段下面覆盖的间隔的元线段的条数,len表示覆盖的长度 
  13. } tree[5005*2*5]; 
  14. int cmp(Line a,Line b) 
  15.     if(a.x!=b.x) 
  16.         return a.x<b.x; 
  17.     else 
  18.         return a.flag>b.flag; 
  19. /* 
  20.  建树不用说,很直观明白!就是以元线段来建树的 而且用到的离散化 
  21. */ 
  22. void build(int l,int r,int num) 
  23.     tree[num].l=l; 
  24.     tree[num].r=r; 
  25.     tree[num].lines=0; 
  26.     tree[num].len=0; 
  27.     tree[num].c=0; 
  28.     tree[num].lb=0; 
  29.     tree[num].rb=0; 
  30.     if(l==r-1) 
  31.         return
  32.     int mid=(l+r)/2; 
  33.     build(l,mid,2*num); 
  34.     build(mid,r,2*num+1); 
  35. /* 
  36.  个人感觉这里写得特别清晰,计算长度也很简单 
  37. */ 
  38. void calen(int num) 
  39.     if(tree[num].c>0) 
  40.         tree[num].len=y[tree[num].r]-y[tree[num].l];//这里典型的以下标来建树 
  41.     else 
  42.     { 
  43.         if(tree[num].l==tree[num].r-1)//元线段 
  44.             tree[num].len=0; 
  45.         else 
  46.             tree[num].len=tree[num*2].len+tree[num*2+1].len; 
  47.     } 
  48.     return
  49. /* 
  50.   这里统计线段的条数不好理解,我看第一种代码的时候就没有看懂 lb与rb的意思! 
  51.   在这里依然有点朦胧,感觉没有理解透! 
  52. */ 
  53. void caline(int num) 
  54.     tree[num].lines=0; 
  55.     tree[num].lb=0; 
  56.     tree[num].rb=0; 
  57.     if(tree[num].c>0) 
  58.     { 
  59.         tree[num].lines=2; 
  60.         tree[num].rb=1; 
  61.         tree[num].lb=1; 
  62.     } 
  63.     else 
  64.     { 
  65.         if(tree[num].l==tree[num].r-1)//元线段 
  66.             tree[num].lines=0; 
  67.         else 
  68.         { 
  69.             tree[num].lines=tree[num*2].lines+tree[2*num+1].lines-2*(tree[num*2].rb&tree[num*2+1].lb); 
  70.             //这里就是lb和rb标记的原因,在合并时使用 
  71.             tree[num].lb=tree[num*2].lb; 
  72.             tree[num].rb=tree[num*2+1].rb; 
  73.         } 
  74.     } 
  75.     return
  76. void update(Line e,int num) 
  77.     if(e.y1==y[tree[num].l]&&e.y2==y[tree[num].r])//与交和并的区别是这里插入到底了, 
  78. //因为这里要计算下面的元线段得条数,所以必须插入到底 
  79.     { 
  80.         tree[num].c+=e.flag; 
  81.         tree[num].lb=1; 
  82.         tree[num].rb=1;//标记当前线段的端点的覆盖情况 
  83.     } 
  84.     else if(e.y2<=y[tree[num*2].r]) 
  85.         update(e,num*2); 
  86.     else if(e.y1>=y[tree[num*2+1].l]) 
  87.         update(e,num*2+1); 
  88.     else 
  89.     { 
  90.         Line tmp=e; 
  91.         int mid=(tree[num].l+tree[num].r)/2; 
  92.         tmp.y2=y[mid]; 
  93.         update(tmp,num*2); 
  94.         tmp=e; 
  95.         tmp.y1=y[mid]; 
  96.         update(tmp,num*2+1); 
  97.     } 
  98.     calen(num);//计算长度 
  99.     caline(num); //计算元线段的条数 
  100. int main() 
  101.     int i,j,n; 
  102.     int x1,y1,x2,y2,t; 
  103.     int lenth,lines,ans; 
  104.     while(scanf("%d",&n)!=EOF) 
  105.     { 
  106.         t=1; 
  107.         for(i=1; i<=n; i++) 
  108.         { 
  109.             scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 
  110.             line[t].x=x1; 
  111.             line[t].y1=y1; 
  112.             line[t].y2=y2; 
  113.             line[t].flag=1;//建立标记要看x的坐标大小 
  114.             line[t+1].x=x2; 
  115.             line[t+1].y1=y1; 
  116.             line[t+1].y2=y2; 
  117.             line[t+1].flag=-1; 
  118.             y[t]=y1; 
  119.             y[t+1]=y2; 
  120.             t=t+2; 
  121.         } 
  122.         sort(line+1,line+t,cmp); 
  123.         sort(y+1,y+t); 
  124.         int l=1; 
  125.         for(i=2; i<t; i++)//线段的离散化 
  126.         { 
  127.             if(y[i]!=y[i-1]) 
  128.                 y[++l]=y[i];//这里因为要看元线段的条数所以将相同的点去掉 
  129.         } 
  130.         build(1,l,1); 
  131.         lenth=0; 
  132.         lines=0; 
  133.         ans=0; 
  134.         for(i=1; i<t; i++) 
  135.         { 
  136.             update(line[i],1); 
  137.             ans+=abs(lenth-tree[1].len)+lines*(line[i].x-line[i-1].x); 
  138.             lenth=tree[1].len; 
  139.             lines=tree[1].lines; 
  140.         } 
  141.         printf("%d\n",ans); 
  142.  
  143.     } 
  144.   //  system("pause"); 

先把代码收藏着吧!以后学习的时候慢慢来参悟!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值