zoukankan      html  css  js  c++  java
  • 线段树专辑—— hdu 1828 Picture

    http://acm.hdu.edu.cn/showproblem.php?pid=1828

    线段树求解重叠矩形周长。这个比求并面积交面积难度大一些,要多想想才能明白

    回忆求并面积的时候的第二种方法,利用线段树树形dp出可以与下一个将要插入的线段去构成并面积的最大y坐标长度,即tree[1].len;

    然后求并面积的时候,只需要将tree[i].len*(line[i+1].x-line[i].x)即可。

    想一想,并面积求的是乘绩,很容易想到周长其实就是求和。也就是y坐标长度加上x坐标的长度。而tree[1].len就已经求的了目前y坐标的可加长度,只需要将它减去上一次得到的tree[1].len再取绝对值即可得到y坐标上的长度增加!  那x坐标的长度如何求呢?这里的方法是为线段树添加一个num域,该域值表示该区间是有几个子区间组成的,例如:

    我们要插入左边矩形的红色那两根线,那么插入后,将得到右边这样的线段树,右边红色的数就是代表num值,[1,5]的那段num==2,说明它是由两个矩形的边组成的(左边那两根红色的),所以每次插入新线段后得到的x坐标的周长可以用 tree[1].num*(line[i+1].x-line[i].x)*2来得到。

    这里只是说了个大概,具体的自己可以研究一下代码

    View Code
      1 #include<iostream>
    2 #include<string>
    3 #include<algorithm>
    4 #include<cmath>
    5 using namespace std;
    6
    7 struct node
    8 {
    9 int l;
    10 int r;
    11 int len; //该区间可与下一个将要插入的线段组成并面积的长度
    12 int cover; //该区间覆盖了几根线段
    13 int num; //记录该区间由几个子区间组成了可与下一个将要插入的线段组成并面积,即可并子区间的数目
    14 int r_cover; //记录该区间右节点是否被可并区间覆盖
    15 int l_cover; //。。。。。坐。。。。。。。。。
    16 };
    17
    18 node tree[100000];
    19 int n;
    20 int yy[10004],len;
    21
    22 struct Line
    23 {
    24 int l;
    25 int r;
    26 int x;
    27 int cover;
    28 };
    29
    30 Line line[10004];
    31
    32 int cmp(Line a,Line b)
    33 {
    34 return a.x<b.x;
    35 }
    36
    37 int find(int x)
    38 {
    39 int l=0,r=len,mid;
    40 while(l<=r)
    41 {
    42 mid=(l+r)/2;
    43 if(yy[mid]==x)
    44 return mid;
    45 if(yy[mid]<x)
    46 l=mid+1;
    47 else
    48 r=mid-1;
    49 }
    50 return l;
    51 }
    52
    53 void build(int i,int l,int r)
    54 {
    55 tree[i].l=l;
    56 tree[i].r=r;
    57 tree[i].cover=tree[i].l_cover=tree[i].r_cover=tree[i].len=tree[i].num=0;
    58 if(l+1==r)
    59 return;
    60 int mid=(l+r)/2;
    61 build(2*i,l,mid);
    62 build(2*i+1,mid,r);
    63 }
    64
    65 void fun(int i)
    66 {
    67 if(tree[i].cover) //整个被覆盖
    68 {
    69 tree[i].len=yy[tree[i].r]-yy[tree[i].l]; //可用长度为整个区间
    70 tree[i].l_cover=tree[i].r_cover=1; //左右节点都被覆盖了
    71 tree[i].num=1; //由一个区间组成,即该区间
    72 }
    73 else if(tree[i].l+1==tree[i].r) //叶子区间
    74 {
    75 tree[i].len=0;
    76 tree[i].l_cover=tree[i].r_cover=0;
    77 tree[i].num=0;
    78 }
    79 else
    80 {
    81 tree[i].len=tree[2*i].len+tree[2*i+1].len; //dp
    82 tree[i].l_cover=tree[2*i].l_cover; //左节点是否覆盖,取决于左子区间的左节点是否被覆盖
    83 tree[i].r_cover=tree[2*i+1].r_cover; //同理
    84 tree[i].num=tree[2*i].num+tree[2*i+1].num-tree[2*i].r_cover*tree[2*i+1].l_cover; //该线段可用长度的区间组成数等于左右子区间的组成数
    85 } //但是,当左右子区间是连续的时候,结果要减一
    86 }
    87
    88 void updata(int i,int l,int r,int w)
    89 {
    90 if(tree[i].l>r || tree[i].r<l)
    91 return;
    92 if(tree[i].l>=l && tree[i].r<=r)
    93 {
    94 tree[i].cover+=w;
    95 fun(i);
    96 return;
    97 }
    98 updata(2*i,l,r,w);
    99 updata(2*i+1,l,r,w);
    100 fun(i);
    101 }
    102
    103 int main()
    104 {
    105 int i,x1,x2,y1,y2,m,a,b;
    106 freopen("in.txt","r",stdin);
    107 while(scanf("%d",&n)!=EOF)
    108 {
    109 m=0;
    110 for(i=0;i<n;i++)
    111 {
    112 scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    113 yy[m]=y1;
    114 line[m].cover=1;
    115 line[m].x=x1;
    116 line[m].l=y1;
    117 line[m++].r=y2;
    118
    119 yy[m]=y2;
    120 line[m].cover=-1;
    121 line[m].x=x2;
    122 line[m].l=y1;
    123 line[m++].r=y2;
    124 }
    125 sort(yy,yy+m);
    126 sort(line,line+m,cmp);
    127 len=1;
    128 for(i=1;i<m;i++)
    129 {
    130 if(yy[i-1]!=yy[i])
    131 yy[len++]=yy[i];
    132 }
    133 len--;
    134 build(1,0,len);
    135 int ans=0,pre=0;
    136 for(i=0;i<m;i++)
    137 {
    138 a=find(line[i].l);
    139 b=find(line[i].r);
    140 updata(1,a,b,line[i].cover);
    141 ans+=abs((tree[1].len-pre)); //加上y坐标上的周长
    142 if(i==m-1)
    143 break;
    144 pre=tree[1].len;
    145 ans+=tree[1].num*(line[i+1].x-line[i].x)*2;//加上x坐标上的周长,因为一个y边连着两个x边,所以乘二
    146 }
    147 printf("%d\n",ans);
    148 }
    149 return 0;
    150 }



  • 相关阅读:
    vue首页组件切换
    vue 页面 添加背景音乐
    vue 新闻列表滚动效果
    vuex中的this.$store.commit
    echarts图例的位置及大小,环图中间字
    octotree — 树形展示 Github 项目代码
    D3 GEO应用专题(一):绘制旋转的3D地球
    vue/cli 3.0脚手架搭建vue项目
    微软锁屏壁纸
    Spring Boot构建RESTful API与单元测试
  • 原文地址:https://www.cnblogs.com/ka200812/p/2247259.html
Copyright © 2011-2022 走看看