[PKU 1177 3277] 线段树(二) {离散化 矩形并问题}

{

承上篇

这次的代码是好久以前写的

感觉比较乱 将就看看吧

这里介绍线段树的删除和一些其他技巧

以求矩形并的周长和面积为例

}

 

上次讨论了利用线段树解决涂色的问题

有一个问题遗留下来

如果我要擦除颜色 该怎么做呢?

很简单 只要插入颜色为0的线段就可以了

因为这里的插入是覆盖型

任何一个区间只有一个颜色 要擦也是一起擦干净

也就是一个节点上至多只被盖着一条线段 以前的线段会被新来的取代

所以这是一个特殊的问题

更为一般的问题是 一个节点上可以有多条线段 互不干涉 地位平等

在线段树上插入若干这样的线段之后

我们还要执行 删除 统计(测度 连续段数等) 操作

 

先看一个具体问题 PKU 1177

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

不过 我们把矩形的坐标范围提升至100w 矩形个数为10w

题意很简单 给定若干个矩形 求矩形周长并

先看图

为了解决这个问题 我们先把一坨一坨的矩形 进行矩形切割

 

我们考虑周长由哪些部分构成

其中 红线是需要统计入周长的竖边 绿线是需要统计入周长的横边

我们称两条蓝线之间的部分为统计区间

我们需要依次统计从左到右的统计区间内的需要计数的矩形边 累加

形象地讲 就是用一根扫描线 从左到右依次扫描

具体实现就是依次遍历那些蓝线然后 累加每个区间的统计结果

  我们任取2个统计区间进行详细讨论 放大前2个统计区间部分

考虑为什么同样是矩形边 红边需要统计而深红色的边不需要统计

我们发现深红色的边包含在第一个矩形内部 也就是夹在第一个矩形两条边之间

继续分析 我们可以知道 横边也是这样

深蓝色边加在统计区间内的两条绿色边之间 属于矩形内部 不需要统计

那么 如何判定是否是红边或绿边呢?

我们在扫描线上投下当前经过扫描线矩形的投影

 

红边必然造成投影的变化 绿边必然在投影上线段的端点处

没有造成投影变化的竖边 肯定在投影内部 也就是在还未扫描完的矩形内部

不在投影线段段端点处的横边 也会夹在在投影线段端点处的两个矩形边内

于是 我们将绿边的长度=统计区间宽*投影连续段数*2

再与红边的长度=与上一个区间投影的差求和 即得到当前区间的统计值 再累加即可

至此 我们只要了解扫描到的矩形的投影的段数N()和总长度M()即可

 

——利用线段树解决这个问题

扫描线从左到右扫描矩形

用线段树记录下扫描线上的投影的情况

当扫描线碰到举行左边的时候就插入这个线段 碰到矩形右边就删除这个线段

用线段树统计出扫描线上的投影的信息

 我们还要重新规划在线段树上的域 除了只有ls[] rs[] l[] r[]需要保留外

我们要添加新的域 覆盖次数cover[] 连续段数ls[] 测度m[](即被覆盖的总长度)

这几个域需要我们实时维护 更需增加维护ls[]的域 lb[] rb[]表示左右端点是否被覆盖

 

介绍一下具体的做法

*事件排序&离散化

 

1 procedure sorty(l,r:longint);
2  var i,j,temp,mid:longint;
3  begin
4 mid:=y[(l+r)shr 1];
5 i:=l; j:=r;
6  repeat
7  while y[i]<mid do inc(i);
8  while mid<y[j] do dec(j);
9  if not(i>j)
10 then begin
11 temp:=y[i];
12 y[i]:=y[j];
13 y[j]:=temp;
14 inc(i); dec(j);
15 end;
16  until i>j;
17  if i<r then sorty(i,r);
18  if l<j then sorty(l,j);
19  end;
20  function find(x:longint):longint;
21  var l,r,mid:longint;
22  begin
23 l:=1; r:=t;
24  while l<=r do
25 begin
26 mid:=(l+r)shr 1;
27 if x<y[mid] then r:=mid-1
28 else if y[mid]<x then l:=mid+1
29 else begin find:=mid; exit; end;
30 end;
31  end;
32  procedure sortindex(l,r:longint);
33  var i,j,temp,mid1,mid2:longint;
34  begin
35 mid1:=index[(l+r)shr 1].x;
36 mid2:=index[(l+r)shr 1].flag;
37 i:=l; j:=r;
38  repeat
39  while (index[i].x<mid1)or((index[i].x=mid1)and(index[i].flag<mid2)) do inc(i);
40  while (mid1<index[j].x)or((mid1=index[j].x)and(mid2<index[j].flag)) do dec(j);
41 if not(i>j)
42 then begin
43 if (index[j].x<index[i].x)or((index[j].x=index[i].x)and(index[j].flag<index[i].flag))
44 then begin
45 temp:=index[i].x;
46 index[i].x:=index[j].x;
47 index[j].x:=temp;
48 temp:=index[i].y1;
49 index[i].y1:=index[j].y1;
50 index[j].y1:=temp;
51 temp:=index[i].y2;
52 index[i].y2:=index[j].y2;
53 index[j].y2:=temp;
54 temp:=index[i].flag;
55 index[i].flag:=index[j].flag;
56 index[j].flag:=temp;
57 end;
58 inc(i); dec(j);
59 end;
60 until i>j;
61 if i<r then sortindex(i,r);
62 if l<j then sortindex(l,j);
63 end;

 

 

 

1 readln(n);
2 t:=0;
3 for i:=1 to n do
4 begin
5 readln(x1[i],y1[i],x2[i],y2[i]);
6 inc(t); y[t]:=y1[i];
7 inc(t); y[t]:=y2[i];
8 end;
9 sorty(1,t);
10 for i:=1 to n do
11 begin
12 y1[i]:=find(y1[i]);
13 y2[i]:=find(y2[i]);
14 end;
15 t:=0;
16 for i:=1 to n do
17 begin
18 inc(t);
19 index[t].x:=x1[i];
20 index[t].y1:=y1[i];
21 index[t].y2:=y2[i];
22 index[t].flag:=-1;
23 inc(t);
24 index[t].x:=x2[i];
25 index[t].y1:=y1[i];
26 index[t].y2:=y2[i];
27 index[t].flag:=1;
28 end;
29 sortindex(1,t);

 

 

  +这是为了能够从左到右扫描

  +由于数据范围有100w 我们需要离散化

    -主程序里1-14行运用快速排序和二分查找将纵坐标坐标离散成数组下标即可

    -排序之后 数组下标可以反映坐标大小 这就是我们需要的离散信息

    -但是我们得记录下原来的值 因为还要统计线段长度

  +称插入或删除一条线段为一个事件 15-29行把所有事件保存起来然后排序

    -注意用flag表示是插入还是删除 如果横坐标相同 先插入后删除

*建树

  +注意建线段树的范围 不是[-100w,100w] 是[0,n]了

*扫描统计

  +插入

 

1 procedure insert(x,a,b:longint);
2 var mid:longint;
3 begin
4 if (a<=tree[x].l)and(tree[x].r<=b)
5 then inc(tree[x].cover)
6 else begin
7 mid:=(tree[x].l+tree[x].r)shr 1;
8 if a<mid then insert(tree[x].lc,a,b);
9 if mid<b then insert(tree[x].rc,a,b);
10 end;
11 if tree[x].cover>0
12 then begin
13 tree[x].m:=y[tree[x].r]-y[tree[x].l];
14 tree[x].lb:=1; tree[x].rb:=1;
15 tree[x].ls:=1;
16 end
17 else if (tree[x].cover=0)and(tree[x].r-tree[x].l=1)
18 then begin
19 tree[x].m:=0;
20 tree[x].lb:=0; tree[x].rb:=0;
21 tree[x].ls:=0;
22 end
23 else begin
24 tree[x].m:=tree[tree[x].lc].m+tree[tree[x].rc].m;
25 tree[x].lb:=tree[tree[x].lc].lb; tree[x].rb:=tree[tree[x].rc].rb;
26 if (tree[tree[x].lc].rb=1)and(tree[tree[x].rc].lb=1)
27 then tree[x].ls:=tree[tree[x].lc].ls+tree[tree[x].rc].ls-1
28 else tree[x].ls:=tree[tree[x].lc].ls+tree[tree[x].rc].ls;
29 end;
30 end;

 

    -(以前的代码 感觉很难看...)

 

    -第4-10行 插入线段的基本语句 具体解释见线段树(一)

    -第11-30行 更新数据域 实质上可以新写一个函数来实现了

      ~前面11-22行判断是否直接赋值

      ~第26-29行分类讨论 lb[] rb[]是否同时为1 判断连续段数的改变

      ~第24行测度直接由儿子更新 求和 25行lb[] rb[]也直接更新即可

  +删除 这里的删除保证以前插入过这条线段

 

1 procedure delete(x,a,b:longint);
2 var mid:longint;
3 begin
4 if (a<=tree[x].l)and(tree[x].r<=b)
5 then dec(tree[x].cover)
6 else begin
7 mid:=(tree[x].l+tree[x].r)shr 1;
8 if a<mid then delete(tree[x].lc,a,b);
9 if mid<b then delete(tree[x].rc,a,b);
10 end;
11 if tree[x].cover>0
12 then begin
13 tree[x].m:=y[tree[x].r]-y[tree[x].l];
14 tree[x].lb:=1; tree[x].rb:=1;
15 tree[x].ls:=1;
16 end
17 else if (tree[x].cover=0)and(tree[x].r-tree[x].l=1)
18 then begin
19 tree[x].m:=0;
20 tree[x].lb:=0; tree[x].rb:=0;
21 tree[x].ls:=0;
22 end
23 else begin
24 tree[x].m:=tree[tree[x].lc].m+tree[tree[x].rc].m;
25 tree[x].lb:=tree[tree[x].lc].lb; tree[x].rb:=tree[tree[x].rc].rb;
26 if (tree[tree[x].lc].rb=1)and(tree[tree[x].rc].lb=1)
27 then tree[x].ls:=tree[tree[x].lc].ls+tree[tree[x].rc].ls-1
28 else tree[x].ls:=tree[tree[x].lc].ls+tree[tree[x].rc].ls;
29 end;
30 end;

 

 

    -所以只要改一改插入

  +统计 根据根节点的测度和连续段数 得出统计值累加

 

1 ans:=0;
2 last:=0;
3 index[t+1].x:=index[t].x;
4 for i:=1 to t do
5 begin
6 if index[i].flag=-1
7 then insert(1,index[i].y1,index[i].y2)
8 else delete(1,index[i].y1,index[i].y2);
9 temp:=index[i+1].x-index[i].x;
10 temp:=temp+temp;
11 temp:=temp*tree[1].ls;
12 temp:=temp+abs(tree[1].m-last);
13 ans:=ans+temp;
14 last:=tree[1].m;
15 end;
16 writeln(ans);

    -运用公式求值

 

这样我们就把求矩形周长并解决了

求矩形面积并更加简单 利用测度即可

问题来源是PKU 3277

两个程序的代码

 

1 {6955221 Master_Chivu 1177 Accepted 1948K 32MS Pascal 4579B 2010-05-24 00:06:55}
2 const maxl=100000;maxn=100000;
3 type
4 treenode=
5 record
6 l,r:longint;
7 ls,lb,rb,m,cover:longint;
8 lc,rc:longint;
9 end;
10 var tree:array[1..maxl shl 1-1]of treenode;
11 x1,x2,y1,y2:array[1..maxn]of longint;
12 y:array[1..maxn shl 1]of longint;
13 index:array[1..maxn shl 1]of record x,y1,y2,flag:longint; end;
14 ans,temp:int64;
15 n,t,i,tot,last:longint;
16 procedure sorty(l,r:longint);
17 var i,j,temp,mid:longint;
18 begin
19 mid:=y[(l+r)shr 1];
20 i:=l; j:=r;
21 repeat
22 while y[i]<mid do inc(i);
23 while mid<y[j] do dec(j);
24 if not(i>j)
25 then begin
26 temp:=y[i];
27 y[i]:=y[j];
28 y[j]:=temp;
29 inc(i); dec(j);
30 end;
31 until i>j;
32 if i<r then sorty(i,r);
33 if l<j then sorty(l,j);
34 end;
35 function find(x:longint):longint;
36 var l,r,mid:longint;
37 begin
38 l:=1; r:=t;
39 while l<=r do
40 begin
41 mid:=(l+r)shr 1;
42 if x<y[mid] then r:=mid-1
43 else if y[mid]<x then l:=mid+1
44 else begin find:=mid; exit; end;
45 end;
46 end;
47 procedure sortindex(l,r:longint);
48 var i,j,temp,mid1,mid2:longint;
49 begin
50 mid1:=index[(l+r)shr 1].x;
51 mid2:=index[(l+r)shr 1].flag;
52 i:=l; j:=r;
53 repeat
54 while (index[i].x<mid1)or((index[i].x=mid1)and(index[i].flag<mid2)) do inc(i);
55 while (mid1<index[j].x)or((mid1=index[j].x)and(mid2<index[j].flag)) do dec(j);
56 if not(i>j)
57 then begin
58 if (index[j].x<index[i].x)or((index[j].x=index[i].x)and(index[j].flag<index[i].flag))
59 then begin
60 temp:=index[i].x;
61 index[i].x:=index[j].x;
62 index[j].x:=temp;
63 temp:=index[i].y1;
64 index[i].y1:=index[j].y1;
65 index[j].y1:=temp;
66 temp:=index[i].y2;
67 index[i].y2:=index[j].y2;
68 index[j].y2:=temp;
69 temp:=index[i].flag;
70 index[i].flag:=index[j].flag;
71 index[j].flag:=temp;
72 end;
73 inc(i); dec(j);
74 end;
75 until i>j;
76 if i<r then sortindex(i,r);
77 if l<j then sortindex(l,j);
78 end;
79 procedure build(a,b:longint);
80 var mid,now:longint;
81 begin
82 inc(tot);
83 now:=tot;
84 tree[now].l:=a;
85 tree[now].r:=b;
86 if b-a>1
87 then begin
88 mid:=(a+b)shr 1;
89 tree[now].lc:=tot+1;
90 build(a,mid);
91 tree[now].rc:=tot+1;
92 build(mid,b);
93 end;
94 end;
95 procedure insert(x,a,b:longint);
96 var mid:longint;
97 begin
98 if (a<=tree[x].l)and(tree[x].r<=b)
99 then inc(tree[x].cover)
100 else begin
101 mid:=(tree[x].l+tree[x].r)shr 1;
102 if a<mid then insert(tree[x].lc,a,b);
103 if mid<b then insert(tree[x].rc,a,b);
104 end;
105 if tree[x].cover>0
106 then begin
107 tree[x].m:=y[tree[x].r]-y[tree[x].l];
108 tree[x].lb:=1; tree[x].rb:=1;
109 tree[x].ls:=1;
110 end
111 else if (tree[x].cover=0)and(tree[x].r-tree[x].l=1)
112 then begin
113 tree[x].m:=0;
114 tree[x].lb:=0; tree[x].rb:=0;
115 tree[x].ls:=0;
116 end
117 else begin
118 tree[x].m:=tree[tree[x].lc].m+tree[tree[x].rc].m;
119 tree[x].lb:=tree[tree[x].lc].lb; tree[x].rb:=tree[tree[x].rc].rb;
120 if (tree[tree[x].lc].rb=1)and(tree[tree[x].rc].lb=1)
121 then tree[x].ls:=tree[tree[x].lc].ls+tree[tree[x].rc].ls-1
122 else tree[x].ls:=tree[tree[x].lc].ls+tree[tree[x].rc].ls;
123 end;
124 end;
125 procedure delete(x,a,b:longint);
126 var mid:longint;
127 begin
128 if (a<=tree[x].l)and(tree[x].r<=b)
129 then dec(tree[x].cover)
130 else begin
131 mid:=(tree[x].l+tree[x].r)shr 1;
132 if a<mid then delete(tree[x].lc,a,b);
133 if mid<b then delete(tree[x].rc,a,b);
134 end;
135 if tree[x].cover>0
136 then begin
137 tree[x].m:=y[tree[x].r]-y[tree[x].l];
138 tree[x].lb:=1; tree[x].rb:=1;
139 tree[x].ls:=1;
140 end
141 else if (tree[x].cover=0)and(tree[x].r-tree[x].l=1)
142 then begin
143 tree[x].m:=0;
144 tree[x].lb:=0; tree[x].rb:=0;
145 tree[x].ls:=0;
146 end
147 else begin
148 tree[x].m:=tree[tree[x].lc].m+tree[tree[x].rc].m;
149 tree[x].lb:=tree[tree[x].lc].lb; tree[x].rb:=tree[tree[x].rc].rb;
150 if (tree[tree[x].lc].rb=1)and(tree[tree[x].rc].lb=1)
151 then tree[x].ls:=tree[tree[x].lc].ls+tree[tree[x].rc].ls-1
152 else tree[x].ls:=tree[tree[x].lc].ls+tree[tree[x].rc].ls;
153 end;
154 end;
155 begin
156 assign(input,'picture.in');
157 reset(input);
158 assign(output,'picture.out');
159 rewrite(output);
160 readln(n);
161 t:=0;
162 for i:=1 to n do
163 begin
164 readln(x1[i],y1[i],x2[i],y2[i]);
165 inc(t); y[t]:=y1[i];
166 inc(t); y[t]:=y2[i];
167 end;
168 sorty(1,t);
169 for i:=1 to n do
170 begin
171 y1[i]:=find(y1[i]);
172 y2[i]:=find(y2[i]);
173 end;
174 t:=0;
175 for i:=1 to n do
176 begin
177 inc(t);
178 index[t].x:=x1[i];
179 index[t].y1:=y1[i];
180 index[t].y2:=y2[i];
181 index[t].flag:=-1;
182 inc(t);
183 index[t].x:=x2[i];
184 index[t].y1:=y1[i];
185 index[t].y2:=y2[i];
186 index[t].flag:=1;
187 end;
188 sortindex(1,t);
189 tot:=0;
190 build(0,t);
191 ans:=0;
192 last:=0;
193 index[t+1].x:=index[t].x;
194 for i:=1 to t do
195 begin
196 if index[i].flag=-1
197 then insert(1,index[i].y1,index[i].y2)
198 else delete(1,index[i].y1,index[i].y2);
199 temp:=index[i+1].x-index[i].x;
200 temp:=temp+temp;
201 temp:=temp*tree[1].ls;
202 temp:=temp+abs(tree[1].m-last);
203 ans:=ans+temp;
204 last:=tree[1].m;
205 end;
206 writeln(ans);
207 close(input);
208 close(output);
209 end.
210
1 {6954141 Master_Chivu 3277 Accepted 4112K 704MS Pascal 3486B 2010-05-23 20:50:27}
2 const maxl=50000; maxn=50000;
3 type
4 treenode=
5 record
6 l,r:longint;
7 cover:longint;
8 lc,rc:longint;
9 end;
10 var tree:array[1..maxl shl 1-1]of treenode;
11 index:array[1..maxn shl 1]of record a,w,flag:longint; end;
12 a,b,w:array[1..maxn]of longint;
13 h:array[0..maxn]of longint;
14 tot,n,i,t:longint; ans,temp:int64;
15 procedure sorth(l,r:longint);
16 var i,j,x,y:longint;
17 begin
18 x:=h[(l+r)shr 1];
19 i:=l; j:=r;
20 repeat
21 while h[i]<x do inc(i);
22 while x<h[j] do dec(j);
23 if not(i>j)
24 then begin
25 y:=h[i];
26 h[i]:=h[j];
27 h[j]:=y;
28 inc(i); dec(j);
29 end;
30 until i>j;
31 if i<r then sorth(i,r);
32 if l<j then sorth(l,j);
33 end;
34 function find(x:longint):longint;
35 var l,r,mid:longint;
36 begin
37 l:=1; r:=n;
38 while l<=r do
39 begin
40 mid:=(l+r)shr 1;
41 if h[mid]<x then l:=mid+1
42 else if h[mid]>x then r:=mid-1
43 else begin find:=mid; exit; end;
44 end;
45 end;
46 procedure sortindex(l,r:longint);
47 var i,j,x1,x2,y:longint;
48 begin
49 x1:=index[(l+r)shr 1].a;
50 x2:=index[(l+r)shr 1].flag;
51 i:=l; j:=r;
52 repeat
53 while (index[i].a<x1)or((index[i].a=x1)and(index[i].flag<x2)) do inc(i);
54 while (x1<index[j].a)or((x1=index[j].a)and(x2<index[j].flag)) do dec(j);
55 if not(i>j)
56 then begin
57 if (index[i].a>index[j].a)
58 or((index[i].a=index[j].a)and(index[i].flag>index[j].flag))
59 then begin
60 y:=index[i].a;
61 index[i].a:=index[j].a;
62 index[j].a:=y;
63 y:=index[i].w;
64 index[i].w:=index[j].w;
65 index[j].w:=y;
66 y:=index[i].flag;
67 index[i].flag:=index[j].flag;
68 index[j].flag:=y;
69 end;
70 inc(i); dec(j);
71 end;
72 until i>j;
73 if i<r then sortindex(i,r);
74 if l<j then sortindex(l,j);
75 end;
76 procedure build(a,b:longint);
77 var mid,now:longint;
78 begin
79 inc(tot);
80 now:=tot;
81 tree[now].l:=a;
82 tree[now].r:=b;
83 if b-a>1
84 then begin
85 mid:=(a+b)shr 1;
86 tree[now].lc:=tot+1;
87 build(a,mid);
88 tree[now].rc:=tot+1;
89 build(mid,b);
90 end;
91 end;
92 procedure insert(x,a,b:longint);
93 var mid:longint;
94 begin
95 if (a<=tree[x].l)and(tree[x].r<=b)
96 then begin
97 inc(tree[x].cover);
98 exit; end;
99 mid:=(tree[x].l+tree[x].r)shr 1;
100 if a<mid then insert(tree[x].lc,a,b);
101 if mid<b then insert(tree[x].rc,a,b);
102 end;
103 procedure delete(x,a,b:longint);
104 var mid:longint;
105 begin
106 if (a<=tree[x].l)and(tree[x].r<=b)
107 then begin
108 dec(tree[x].cover);
109 exit; end;
110 mid:=(tree[x].l+tree[x].r)shr 1;
111 if a<mid then delete(tree[x].lc,a,b);
112 if mid<b then delete(tree[x].rc,a,b);
113 end;
114 function count(x:longint):longint;
115 var ans:longint;
116 begin
117 if tree[x].cover>0
118 then begin
119 count:=h[tree[x].r]-h[tree[x].l];
120 exit; end
121 else begin
122 ans:=0;
123 if tree[x].lc<>0 then ans:=ans+count(tree[x].lc);
124 if tree[x].rc<>0 then ans:=ans+count(tree[x].rc);
125 count:=ans; end;
126 end;
127 begin
128 assign(input,'rectangle.in');
129 reset(input);
130 assign(output,'rectangle.out');
131 rewrite(output);
132 readln(n);
133 for i:=1 to n do
134 begin
135 readln(a[i],b[i],w[i]);
136 h[i]:=w[i];
137 end;
138 sorth(1,n);
139 for i:=1 to n do
140 w[i]:=find(w[i]);
141 t:=0;
142 for i:=1 to n do
143 begin
144 inc(t); index[t].a:=a[i]; index[t].w:=w[i]; index[t].flag:=1;
145 inc(t); index[t].a:=b[i]; index[t].w:=w[i]; index[t].flag:=-1;
146 end;
147 sortindex(1,t);
148 tot:=0;
149 build(0,n);
150 ans:=0;
151 index[t+1].a:=index[t].a;
152 for i:=1 to t do
153 begin
154 if index[i].flag=1
155 then insert(1,0,index[i].w)
156 else delete(1,0,index[i].w);
157 temp:=index[i+1].a-index[i].a;
158 temp:=temp*count(1);
159 ans:=ans+temp;
160 end;
161 writeln(ans);
162 close(input);
163 close(output);
164 end.
165

 

这个问题还是推荐去读一下 陈宏大神的论文

下一篇讨论牛B的Lazy-tag思想

 

Bob HAN 原创 转载请注明出处 http://www.cnblogs.com/Booble/

posted on 2010-10-10 14:08  Master_Chivu  阅读(4045)  评论(1编辑  收藏  举报

导航