POJ_3470 Walls 【离散化+扫描线+线段树】
一、题面
二、分析
POJ感觉是真的老了。
这题需要一些预备知识:扫描线,离散化,线段树。线段树是解题的关键,因为这里充分利用了线段树区间修改的高效性,再加上一个单点查询。
为什么需要离散化?
坐标太分散了,据说可以到 long long,但是就这么多个点,所以离散化一下,方便处理。
为什么用扫描线算法?
用扫描线,可以方便的求出一个bird到wall的距离,因为是顺着一个方向扫的(这题需要从四个方向扫),所以保证了准确性和高效性。
为什么用线段树?
用线段树非常明显,因为墙有这么多,并且结合扫描线,墙可能会有重叠部分,而线段树的lazy标记用法刚好可以完美的使用。
然后就是一些思维方面的了,因为bird可以朝4个方向飞,所以需要从4个方向扫,如果不从4个方向扫,每次处理一个bird非常不好处理。
然后就是写代码的时候要细心,可能有很多细节问题。
三、AC代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步