线段树专辑—— 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 }



原文地址:https://www.cnblogs.com/ka200812/p/2247312.html