zoukankan      html  css  js  c++  java
  • 线段树专辑—— pku 1436 Horizontally Visible Segments

    http://poj.org/problem?id=1436

    这道题最终就是问,两两可见的三条线段组有多少组。所谓两两可见,指的是某一条横线可以连接到两条线段,并且中途不会碰到其他线段。

    很显然又是一道区间染色的题目嘛,关于区间染色的解法,不多说了,这里说关键的!

    这题就sample来说,按它给的数据来建树的话,最右边的和最左边的是无法触碰到一起的,因为第二根线段和第三根线段之间只留下了[2,3]这样的小缝隙,而这样的小缝隙在线段树建树的过程中,是会被二分忽略掉的。看图

    上面黑色的,就是题目所给的sample所对应的坐标系上的图样,而下面的红色的,就是上面的黑色的在线段树中所对应的图样。

    很显然最右边的竖线和第一根竖线相连时[2,3]这条缝隙给忽略过去了! 导致它们无法相连...

    解决的办法是将所给的所有数据都乘以2,这样就空隙[2,3]就会变成区间[4,6],这样就可以过去了!

    将所给的竖直线段从左到右排序后一次对线段树进行染色,染色之前进行一次查找,看看新的颜色能够更新那些旧的颜色,能更新,就说明两两可见!最后穷举每条边即可!

    View Code
      1 #include<iostream>
    2 #include<string>
    3 #include<cmath>
    4 #include<algorithm>
    5 #include<vector>
    6 using namespace std;
    7
    8 struct node
    9 {
    10 int l;
    11 int r;
    12 int cover;
    13 };
    14
    15 node tree[100000];
    16 int n;
    17 int v[8002];
    18
    19 struct Line
    20 {
    21 int x;
    22 int y1;
    23 int y2;
    24 };
    25
    26 Line line[8001];
    27
    28 int cmp(Line a,Line b)
    29 {
    30 return a.x<b.x;
    31 }
    32
    33 vector<int>map[8001];
    34
    35 void build(int i,int l,int r)
    36 {
    37 tree[i].l=l;
    38 tree[i].r=r;
    39 tree[i].cover=0;
    40 if(l==r)
    41 return;
    42 int mid=(l+r)/2;
    43 build(2*i,l,mid);
    44 build(2*i+1,mid+1,r);
    45 }
    46
    47 void updata(int i,int l,int r,int w)
    48 {
    49 if(tree[i].l>r || tree[i].r<l)
    50 return;
    51 if(tree[i].l>=l && tree[i].r<=r)
    52 {
    53 tree[i].cover=w;
    54 return;
    55 }
    56 if(tree[i].cover!=-1)
    57 {
    58 tree[2*i].cover=tree[2*i+1].cover=tree[i].cover;
    59 tree[i].cover=-1;
    60 }
    61 updata(2*i,l,r,w);
    62 updata(2*i+1,l,r,w);
    63 }
    64
    65 void find(int i,int l,int r,int x)
    66 {
    67 if(tree[i].l>r || tree[i].r<l)
    68 return;
    69 if(tree[i].cover!=-1 && tree[i].cover) //找到一种旧颜色,更新,并建边
    70 {
    71 if(v[tree[i].cover]!=x)
    72 {
    73 v[tree[i].cover]=x;
    74 map[x].push_back(tree[i].cover);
    75 }
    76 return;
    77 }
    78 if(tree[i].l==tree[i].r)
    79 return;
    80 find(2*i,l,r,x);
    81 find(2*i+1,l,r,x);
    82 }
    83
    84 int main()
    85 {
    86 int cas,i,j,k,a,b,l;
    87 freopen("in.txt","r",stdin);
    88 scanf("%d",&cas);
    89 while(cas--)
    90 {
    91 build(1,1,16000);
    92 scanf("%d",&n);
    93 for(i=0;i<n;i++)
    94 {
    95 map[i+1].clear();
    96 scanf("%d%d%d",&line[i].y1,&line[i].y2,&line[i].x);
    97 }
    98 sort(line,line+n,cmp);
    99 memset(v,0,sizeof(v));
    100 for(i=0;i<n;i++)
    101 {
    102 find(1,line[i].y1*2,line[i].y2*2,i+1);
    103 updata(1,line[i].y1*2,line[i].y2*2,i+1);
    104 }
    105 int ans=0;
    106 for(i=n;i>=1;i--) //穷举每一条边
    107 {
    108 for(j=0;j!=map[i].size();j++)
    109 {
    110 a=map[i][j];
    111 for(k=0;k!=map[a].size();k++)
    112 {
    113 b=map[a][k];
    114 for(l=0;l!=map[i].size();l++)
    115 if(map[i][l]==b)
    116 ans++;
    117 }
    118 }
    119 }
    120 printf("%d\n",ans);
    121 }
    122 return 0;
    123 }



  • 相关阅读:
    html页面原生video标签隐藏下载按钮
    css解决多行溢出显示省略号
    移动端轮播图vue-awesome-swiper
    日常踩坑 — 相邻元素之间的margin合并问题。
    (a ==1 && a== 2 && a==3) 有可能是 true 吗?
    如何生成SSH key及查看SSH key
    端口号被占用报错解决方法。
    基于vue开发的element-ui树形控件报错问题解决
    Win10 桌面 通知中心 无法打开
    SolidWorks 杂
  • 原文地址:https://www.cnblogs.com/ka200812/p/2247312.html
Copyright © 2011-2022 走看看