zoukankan      html  css  js  c++  java
  • [扫描线+树状数组]解决矩形包含点的问题

      今天做到第二题,大部分的思路都理解了之后最后剩下一个问题

      zzx:“然后扫描线+树状数组搞一下就好了”

      看到这两个算法就产生了一种我肯定会的错觉...

      然后后来发现并不会的时候很惭愧...

      然后十分感谢YDC,在之前完全陌生的情况下 我去问这样一个问题

      超级超级超级耐心地给我解答 

      我问着每一个他们看起来显然的具体处理方法

      突然发现真的像张老师说的:“你普及升提高的这条路没有怎么走,中间那块知识是空着的啊”

      今天才切实体会到...但是或许正是这样今天学到这样的一个东西更让我觉得开心吧


      树状数组解决一维点线包含问题

      事实上现在印象非常深刻,初二的时候做过一道苹果的题目,就是运用到树状数组

      也是添加线段,然后查询当前点是否有苹果,当时可能还比较小

      对这样解决方法并不是理解得十分透彻

      1)添加线段(l,r):put(l,1);put(r+1,-1);

      2) 删除线段(l,r):put(l,-1);put(r+1,1);

      3) 横坐标为x的点被覆盖的次数 = get(x);

      其实很好理解...如果把树状数组理解成前缀和一样的东西,相当于x前有多少个左端点,多少个右端点

      然后每一个左端点和一个右端点相互抵消

      然后我们拓展到二维的情况

      添加扫描线即可

      对于一系列横坐标为x的点,我们需要在树状数组中的

      是左边界<=x,右边界>x的矩形

      1)我们只需要把还未添加进来的,左边界满足要求的添加进来

      2)把已经添加进来的,右边界不满足要求的删掉即可

      第一种情况显然是满足单调性的,然而第二种实际上也是

      因为右边界都不满足要求了,即<x,那么左边界也一定<x,也就是这个矩形必然添加进来了

      然后对于每一个矩形,其y坐标的区间进行树状数组的删添操作

      然后对于这些点,get(y)就是被覆盖的次数

      并没有找到这样的裸题,于是写了个暴力对拍

      需要注意:

      1)坐标往往需要离散化(当然为了偷懒这次就没写离散

      2)一些点或者矩形有必要需要保存id,因为排序之后输出可能会影响答案(在某些题目中

      3)如果题目中并没有明确告诉左上角和右下角的顺序,要记得交换

      4)若边界上的点不算,则需要注意更多的细节

      1 program sweep;
      2 const maxn = 10010;
      3 var i,n,m,j,k,head,tail:longint;
      4     a,c:array[-1..maxn]of record x1,y1,x2,y2:longint;end;
      5     b:array[-1..maxn]of record x,y,id:longint;end;
      6     f,tr:array[-1..maxn]of longint;
      7 
      8 procedure qsort1(L,R:longint);
      9 var i,j,mid:longint;
     10 begin
     11     i:=L;j:=R;mid:=a[random(R-L+1)+L].x1;
     12     repeat
     13         while (i<R)and(a[i].x1<mid) do inc(i);
     14         while (L<j)and(a[j].x1>mid) do dec(j);
     15         if i<=j then
     16         begin
     17             a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
     18             inc(i);dec(j);
     19         end;
     20     until i>j;
     21     if i<R then qsort1(i,R);
     22     if L<j then qsort1(L,j);
     23 end;
     24 
     25 procedure qsort2(L,R:longint);
     26 var i,j,mid:longint;
     27 begin
     28     i:=L;j:=R;mid:=b[random(R-L+1)+L].x;
     29     repeat
     30         while (i<R)and(b[i].x<mid) do inc(i);
     31         while (L<j)and(b[j].x>mid) do dec(j);
     32         if i<=j then
     33         begin
     34             b[0]:=b[i];b[i]:=b[j];b[j]:=b[0];
     35             inc(i);dec(j);
     36         end;
     37     until i>j;
     38     if i<R then qsort2(i,R);
     39     if L<j then qsort2(L,j);
     40 end;
     41 
     42 procedure qsort3(L,R:longint);
     43 var i,j,mid:longint;
     44 begin
     45     i:=L;j:=R;mid:=c[random(R-L+1)+L].x2;
     46     repeat
     47         while (i<R)and(c[i].x2<mid) do inc(i);
     48         while (L<j)and(c[j].x2>mid) do dec(j);
     49         if i<=j then
     50         begin
     51             c[0]:=c[i];c[i]:=c[j];c[j]:=c[0];
     52             inc(i);dec(j);
     53         end;
     54     until i>j;
     55     if i<R then qsort3(i,R);
     56     if L<j then qsort3(L,j);
     57 end;
     58 
     59 procedure put(x,y:longint);
     60 begin
     61     while x<=maxn do
     62     begin
     63         inc(tr[x],y);
     64         x:=x+x and (-x);
     65     end;
     66 end;
     67 
     68 function get(x:longint):longint;
     69 begin
     70     get:=0;
     71     while x<>0 do
     72     begin
     73         inc(get,tr[x]);
     74         x:=x-x and (-x);
     75     end;
     76 end;
     77 
     78 begin
     79     assign(input,'sweep.in');reset(input);
     80         assign(output,'sweep.out');rewrite(output);
     81     readln(n,m);
     82     for i:=1 to n do readln(a[i].x1,a[i].y1,a[i].x2,a[i].y2);
     83     //读入矩形左上角和右下角(为了偷懒没有交换23333
     84     for i:=1 to m do begin readln(b[i].x,b[i].y);b[i].id:=i;end;
     85     //读入点坐标
     86     qsort1(1,n);  //按照做边界排序矩形 
     87     qsort2(1,m);
     88     c:=a;qsort3(1,n); //按照右边界排序矩形
     89     head:=1;tail:=1;i:=1;
     90     while i<=m do
     91     begin
     92         while (tail<=n)and(a[tail].x1<=b[i].x) do
     93         begin
     94             put(a[tail].y1,1);
     95             put(a[tail].y2+1,-1);
     96             inc(tail);
     97         end;
     98         //把左边界包含点的矩形添加进来
     99         while (head<=n)and(c[head].x2<b[i].x) do
    100         begin
    101             put(c[head].y1,-1);
    102             put(c[head].y2+1,1);
    103             inc(head);
    104         end;
    105         //把右边界已经跳出点的矩形删去
    106         j:=i+1;
    107         while (j<=m)and(b[j].x=b[i].x) do inc(j);
    108         for k:=i to j-1 do f[b[k].id]:=get(b[k].y);
    109         i:=j;
    110     end;
    111     for i:=1 to m do writeln(f[i]);
    112 end.

      #在做题之前多想一些细节总是好的

       

      21/.Aprl

  • 相关阅读:
    模板库
    LCT小结
    BZOJ1502: [NOI2005]月下柠檬树
    技术资料分享
    ORM介紹及ORM優點、缺點
    依賴注入入門——Unity(二)
    面向切面編程入門(一)
    依賴注入入門——Unity(一)
    WCF、.Net Remoting、Web Service概念及区别
    深入设计模式(四)——建造者模式
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4445430.html
Copyright © 2011-2022 走看看