POJ_3470 Walls 【离散化+扫描线+线段树】

一、题面

POJ3470

二、分析

POJ感觉是真的老了。

这题需要一些预备知识:扫描线,离散化,线段树。线段树是解题的关键,因为这里充分利用了线段树区间修改的高效性,再加上一个单点查询。

为什么需要离散化?

坐标太分散了,据说可以到 long long,但是就这么多个点,所以离散化一下,方便处理。

为什么用扫描线算法?

用扫描线,可以方便的求出一个bird到wall的距离,因为是顺着一个方向扫的(这题需要从四个方向扫),所以保证了准确性和高效性。

为什么用线段树?

用线段树非常明显,因为墙有这么多,并且结合扫描线,墙可能会有重叠部分,而线段树的lazy标记用法刚好可以完美的使用。

然后就是一些思维方面的了,因为bird可以朝4个方向飞,所以需要从4个方向扫,如果不从4个方向扫,每次处理一个bird非常不好处理。

然后就是写代码的时候要细心,可能有很多细节问题。

扫描二维码关注公众号,回复: 5789182 查看本文章

三、AC代码

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <vector>
  4 #include <algorithm>
  5 #include <fstream>
  6 #include <cstring>
  7 #include <cmath>
  8 using namespace std;
  9 
 10 #define Lson(x) (x<<1)      //左儿子
 11 #define Rson(x) (x<<1|1)      //左儿子
 12 #define Mid(l, r) ( (l+r)>>1 )
 13 #define LL long long
 14 const int MAXN = 2e5 + 15;
 15 int N, M;       //N is the number of wall
 16 int ans[MAXN];
 17 vector<LL> cor_x, cor_y;
 18 struct Wall
 19 {
 20     LL x1, y1;
 21     LL x2, y2;
 22 }W[MAXN];
 23 struct Bird
 24 {
 25     LL x, y;
 26 }B[MAXN];
 27 struct Dist
 28 {
 29     int id;
 30     LL dist;
 31     Dist()
 32     { 
 33         //这里必须用long long 的无穷大,因为给的数据会超过int
 34         //找这个WA点找了很久
 35         dist = __LONG_LONG_MAX__;
 36     }
 37 }D[MAXN];
 38 enum Type
 39 {
 40     WALL, BIRD
 41 };
 42 
 43 struct Object  //处理对象
 44 {
 45     Type type;
 46     int id;         //bird's or wall's id
 47     int x, y1, y2;
 48     Object(int x, int y1, int y2, int id, Type type):x(x),y1(y1),y2(y2),id(id),type(type){}
 49     bool operator < (const Object &t)const
 50     {
 51         return x < t.x;
 52     }
 53 };
 54 
 55 struct SegTree
 56 {
 57     //Value的值表示线段树维护区间的墙的id
 58     int Left[MAXN<<2], Right[MAXN<<2], Value[MAXN<<2];
 59     //线段树初始化
 60     void init(int p, int l, int r)
 61     {
 62         Left[p] = l;
 63         Right[p] = r;
 64         Value[p] = 0;
 65         if(l == r)
 66             return;
 67         init(Lson(p), l, Mid(l, r));
 68         init(Rson(p), Mid(l, r) + 1, r);
 69     }
 70     //出现了墙,则维护区间
 71     void update(int p, int l, int r, int id)
 72     {
 73         if(Left[p] == l && Right[p] == r)
 74         {
 75             Value[p] = id;
 76             return;
 77         }
 78         if(Value[p] > 0)
 79         {
 80             Value[Lson(p)] = Value[p];
 81             Value[Rson(p)] = Value[p];
 82             Value[p] = 0;   //一定记得清0
 83         }
 84         // int mid = Mid(l, r);
 85         int mid = Mid(Left[p], Right[p]);
 86         if(l > mid)
 87         {
 88             update(Rson(p), l, r, id);
 89         }
 90         else if(r <= mid)
 91         {
 92             update(Lson(p), l, r, id);
 93         }
 94         else
 95         {
 96             update(Lson(p), l, mid, id);
 97             update(Rson(p), mid + 1, r, id);
 98         }
 99     }
100     //出现了bird, 在线段树中寻找合适的wall被撞
101     // loc 如果是沿x轴飞,那么loc应该是y值,只有这样才能保证撞的有效
102     int find(int p, int loc)
103     {
104         if(Left[p] == Right[p] && Left[p] == loc)
105             return Value[p];
106         if(Value[p] > 0)
107         {
108             Value[Lson(p)] = Value[p];
109             Value[Rson(p)] = Value[p];
110             Value[p] = 0;       //一定记得清0
111         }
112         int mid = Mid(Left[p], Right[p]);
113         if(loc > mid)
114         {
115             return find(Rson(p), loc);
116         }
117         else
118         {
119             return find(Lson(p), loc);
120         }
121     }
122 }STree;
123 
124 
125 //计算距离
126 LL cal_dis(bool dir, int x1, int x2)
127 {
128     LL d1, d2;
129     if(dir)
130     {
131         d1 = cor_x[x1 - 1];
132         d2 = cor_x[x2 - 1];
133     }
134     else
135     {
136         d1 = cor_y[x1 - 1];
137         d2 = cor_y[x2 - 1];
138     }
139     d1 = d1 - d2;
140     if(d1 < 0)
141         return -d1;
142     else
143         return d1;
144 }
145 
146 void scan(const vector<Object> &arr, bool dir)   //dir表示方向
147 {
148     STree.init(1, 1, max(cor_x.size(), cor_y.size()) + 15);
149     vector<Object>::const_iterator itr;
150     for(itr = arr.begin(); itr != arr.end(); itr++)
151     {
152         if(itr->type == WALL)
153         {
154             STree.update(1, itr->y1, itr->y2, itr->id);
155         }
156         else
157         {
158             int pos = STree.find(1, itr->y1);
159             
160             if(pos)
161             {//一定要保证墙存在!
162                 LL len;
163                 if(dir)         // dir = 1 表示沿x轴方向
164                     //len = cal_dis(dir, itr->x, W[pos].x1);
165                     len = min( cal_dis(true, W[pos].x1, itr->x), cal_dis(true, W[pos].x2, itr->x) );
166             
167                 else
168                     //len = cal_dis(dir, itr->x, W[pos].y1);
169                     len = min( cal_dis(false, W[pos].y1, itr->x), cal_dis(false, W[pos].y2, itr->x) );
170                 if(len < D[itr->id].dist)
171                 {
172                     D[itr->id].dist = len;
173                     D[itr->id].id = pos;
174                 }
175             }
176         }
177     }
178      
179 }
180 
181 
182 void fly_x()      //假设现在bird都是沿着x轴方向飞行
183 {
184     vector<Object> T;      //存储扫描时要处理的对象
185     for(int i = 1; i <= N; i++)
186     {
187         T.push_back(Object(W[i].x1, W[i].y1, W[i].y2, i, WALL) );
188         if(W[i].x1 != W[i].x2)      //必须要加末端,因为bird可能在延长线上
189         {
190             T.push_back(Object(W[i].x2, W[i].y1, W[i].y2, i, WALL) );
191         }
192     }
193     for(int i = 1; i <= M; i++)
194     {
195         T.push_back(Object(B[i].x, B[i].y, 0, i, BIRD) );
196     }
197     sort(T.begin(), T.end());
198     scan(T, true);
199     reverse(T.begin(), T.end());
200     scan(T, true);
201 }
202 
203 void fly_y()      //假设现在bird都是沿着y轴方向飞行
204 {
205     vector<Object> T;      //存储扫描时要处理的对象
206     for(int i = 1; i <= N; i++)
207     {
208         T.push_back(Object(W[i].y1, W[i].x1, W[i].x2, i, WALL) );
209         if(W[i].y1 != W[i].y2)
210         {
211             T.push_back(Object(W[i].y2, W[i].x1, W[i].x2, i, WALL) );
212         } 
213     }
214     for(int i = 1; i <= M; i++)
215     {
216         T.push_back(Object(B[i].y, B[i].x, 0, i, BIRD) );      //注意顺序
217     }
218     sort(T.begin(), T.end());
219     scan(T, false);
220     reverse(T.begin(), T.end());
221     scan(T, false);
222 }
223 
224 void discretization()   //离散化处理
225 {
226     sort(cor_x.begin(), cor_x.end());
227     sort(cor_y.begin(), cor_y.end());
228     cor_x.erase(unique(cor_x.begin(), cor_x.end() ), cor_x.end() );
229     cor_y.erase(unique(cor_y.begin(), cor_y.end() ), cor_y.end() ); 
230     for(int i = 1; i <= N; i++)
231     {
232         W[i].x1 = lower_bound(cor_x.begin(), cor_x.end(), W[i].x1) - cor_x.begin() + 1;
233         W[i].x2 = lower_bound(cor_x.begin(), cor_x.end(), W[i].x2) - cor_x.begin() + 1;
234         W[i].y1 = lower_bound(cor_y.begin(), cor_y.end(), W[i].y1) - cor_y.begin() + 1;
235         W[i].y2 = lower_bound(cor_y.begin(), cor_y.end(), W[i].y2) - cor_y.begin() + 1;
236     }
237     for(int i = 1; i <= M; i++)
238     {
239         B[i].x = lower_bound(cor_x.begin(), cor_x.end(), B[i].x) - cor_x.begin() + 1;
240         B[i].y = lower_bound(cor_y.begin(), cor_y.end(), B[i].y) - cor_y.begin() + 1;
241     } 
242 }
243 
244 int main()
245 {
246 
247     //freopen("input.txt", "r", stdin);
248     scanf("%d %d", &N, &M);
249     for(int i = 1; i <= N; i++)
250     {
251         scanf("%I64d %I64d %I64d %I64d", &W[i].x1, &W[i].y1, &W[i].x2, &W[i].y2);
252         if(W[i].x1 > W[i].x2)   swap(W[i].x1, W[i].x2);
253         if(W[i].y1 > W[i].y2)   swap(W[i].y1, W[i].y2);
254         cor_x.push_back(W[i].x1);
255         cor_x.push_back(W[i].x2);
256         cor_y.push_back(W[i].y1);
257         cor_y.push_back(W[i].y2);
258     }
259     for(int j = 1; j <= M; j++)
260     {
261         scanf("%I64d %I64d", &B[j].x, &B[j].y);
262         cor_x.push_back(B[j].x);
263         cor_y.push_back(B[j].y);
264     }
265     discretization();
266     fly_x();
267     fly_y();
268     memset(ans, 0, sizeof(ans));
269     for(int i = 1; i <= M; i++)
270     {
271         ans[ D[i].id ]++;
272     }
273     for(int i = 1; i <= N; i++)
274     {
275         printf("%d\n", ans[i]);
276     }
277     return 0;
278 }
View Code

猜你喜欢

转载自www.cnblogs.com/dybala21/p/10659648.html
今日推荐