zoukankan      html  css  js  c++  java
  • POJ_3470 Walls 【离散化+扫描线+线段树】

    一、题面

    POJ3470

    二、分析

    POJ感觉是真的老了。

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

    为什么需要离散化?

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

    为什么用扫描线算法?

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

    为什么用线段树?

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

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

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

    三、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
    ", ans[i]);
    276     }
    277     return 0;
    278 }
    View Code
  • 相关阅读:
    常用的SQL优化
    mysql索引详细介绍
    作业2
    作业1
    python学习笔记(11)文件操作
    python学习笔记(10)函数(二)
    python学习笔记(9)函数(一)
    C#的dictionary使用总结
    常用的类型转化
    我的动态库“情节”
  • 原文地址:https://www.cnblogs.com/dybala21/p/10659648.html
Copyright © 2011-2022 走看看