zoukankan      html  css  js  c++  java
  • BZOJ2092 : [Poi2010]Lamp

    假设从光源$(0,0)$射出的一束光第一次碰到右边墙上的$(x,y)$,那么第$k$次的坐标是$(kx,ky)$。

    如果在第$k$次到达了左边某个点且$k$是$2^d imes o$的形式,其中$o$是奇数,那么在第$2^d$次一定也能到达这个点。

    枚举所有不超过最大坐标两倍的$2^d$,判断左边每个窗户在$2^d$次能否被照亮。

    那么右边要存在一个矩形覆盖$(frac{x}{2^d-1},frac{y}{2^d-1})$,左边要存在一个矩形覆盖$(frac{x}{2^d-2},frac{y}{2^d-2})$,右边要存在一个矩形覆盖$(frac{x}{2^d-3},frac{y}{2^d-3})$,左边要存在一个矩形覆盖$(frac{x}{2^d-4},frac{y}{2^d-4})$...

    把每个矩形缩放成$O(2^d)$份,并把左右两面墙合并,那么如果左边某个矩形内部存在一个至少被$2^d$个矩形覆盖的点则可行,注意这里可以用分数类做到全整数计算。

    扫描线+线段树维护扫描线上每个区间内被覆盖次数的最大值,同时将每个左边的矩形拆成线段树上$O(log n)$条线段放入。

    每次处理完修改操作后,从线段树根节点开始遍历,如果区间最大值$<2^d$或者当前子树内没有任何线段则return,这样即可在总计$O(nlog n)$的时间里找出所有被照亮的矩形。

    时间复杂度$O(nwlog n)$,其中$w$为坐标范围。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=605,M=4200005,MX=1025;
    int n,m,K,i,ans[N],fin,cy,ce,_,f[MX],C,D,P,pl[N<<1][MX],pr[N<<1][MX];
    int py[1400000],l[N<<1][MX],r[N<<1][MX],del[N],cur;
    bool has[M];int tag[M],val[M],g[M],v[30005],nxt[30005],ed;
    struct Rect{int x1,y1,x2,y2;}a[N],b[N];
    struct E{int x,t;E(){}E(int _x,int _t){x=_x,t=_t;}}e[1400000];
    inline int sgn(int a,int b){
      int t=(a>>11)*(b&2047)-(b>>11)*(a&2047);
      if(!t)return 0;
      return t<0?-1:1;
    }
    inline bool cmpf(int a,int b){return sgn(a,b)<0;}
    inline bool cmpe(const E&a,const E&b){return sgn(a.x,b.x)<0;}
    inline void addrect(const Rect&a,int b,int x){
      l[x][b]=py[++cy]=a.y1<<11|b;
      r[x][b]=py[++cy]=a.y2<<11|b;
      e[++ce]=E(a.x1<<11|b,x<<11|b);
      e[++ce]=E(a.x2<<11|b,(-x)<<11|b);
    }
    inline int lower(int x){
      int l=1,r=cy,mid;
      while(1){
        if(!sgn(x,py[mid=(l+r)>>1]))return mid;
        if(sgn(x,py[mid])<0)r=mid-1;else l=mid+1;
      }
    }
    void change(int x,int a,int b){
      if(C<=a&&b<=D){tag[x]+=P;val[x]+=P;return;}
      int mid=(a+b)>>1;
      if(C<=mid)change(x<<1,a,mid);
      if(D>mid)change(x<<1|1,mid+1,b);
      val[x]=max(val[x<<1],val[x<<1|1])+tag[x];
    }
    void ins(int x,int a,int b){
      has[x]=1;
      if(C<=a&&b<=D){v[++ed]=P;nxt[ed]=g[x];g[x]=ed;return;}
      int mid=(a+b)>>1;
      if(C<=mid)ins(x<<1,a,mid);
      if(D>mid)ins(x<<1|1,mid+1,b);
    }
    void dfs(int x,int a,int b,int t){
      if(!has[x]||val[x]+t<K)return;
      for(int i=g[x];i;i=nxt[i])if(sgn(del[v[i]],cur)>0)ans[v[i]]=1;
      g[x]=0;
      if(a==b){has[x]=0;return;}
      int mid=(a+b)>>1;
      t+=tag[x];
      dfs(x<<1,a,mid,t),dfs(x<<1|1,mid+1,b,t);
      has[x]=has[x<<1]|has[x<<1|1];
    }
    void solve(int _K){
      int i,j,o,x,y;
      K=_K;
      for(i=1;i<=n;i++)if(!ans[i]&&f[a[i].y2]>=K)break;
      if(i>n)return;
      ce=cy=0;
      for(i=1;i<=n;i++){
        for(j=K;j>0;j-=2){
          if(j<K&&!ans[i])break;
          addrect(a[i],j,i);
        }
        if(!ans[i])del[i]=a[i].x2<<11|K;
      }
      for(i=1;i<=m;i++)for(j=K-1;j>0;j-=2)addrect(b[i],j,i+n);
      sort(py+1,py+cy+1,cmpf);
      for(_=0,i=1;i<=cy;i++)if(i==1||sgn(py[_],py[i]))py[++_]=py[i];
      cy=_--;
      for(i=1;i<=n;i++)for(j=K;j>0;j-=2){
        if(j<K&&!ans[i])break;
        pl[i][j]=lower(l[i][j]),pr[i][j]=lower(r[i][j])-1;
      }
      for(i=n+1;i<=n+m;i++)for(j=K-1;j>0;j-=2)pl[i][j]=lower(l[i][j]),pr[i][j]=lower(r[i][j])-1;
      sort(e+1,e+ce+1,cmpe);
      ed=0;
      for(j=1;j<=_;j<<=1);j<<=1;
      memset(tag,0,j*sizeof(int));
      memset(val,0,j*sizeof(int));
      memset(g,0,j*sizeof(int));
      memset(has,0,j*sizeof(bool));
      for(i=1;i<=ce;i=j){
        cur=e[i].x;
        for(j=i;j<=ce&&!sgn(cur,e[j].x);j++){
          o=e[j].t;
          x=o>>11;
          y=o&2047;
          if(o>0)o=1;else x=-x,o=-1;
          C=pl[x][y],D=pr[x][y],P=o;
          change(1,1,_);
          if(x<=n&&o==1&&!ans[x]&&y==K)P=x,ins(1,1,_);
        }
        dfs(1,1,_,0);
      }
    }
    int main(){
      for(f[1]=i=2;i<MX;i++)f[i]=f[i>>1]<<1;
      scanf("%d%d",&n,&m);
      for(i=1;i<=n;i++)scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
      for(i=1;i<=m;i++)scanf("%d%d%d%d",&b[i].x1,&b[i].y1,&b[i].x2,&b[i].y2);
      for(i=2;i<MX;i<<=1)solve(i);
      for(i=1;i<=n;i++)if(ans[i])fin++;
      printf("%d
    ",fin);
      for(i=1;i<=n;i++)if(ans[i])printf("%d ",i);
      return 0;
    }
    

      

  • 相关阅读:
    -webkit-line-clamp 多行文字溢出...
    整理一些知识碎片...
    localstorage sessionstorage和cookie的区别
    数据结构 --- Set
    Iterator(遍历器)
    ES6数组方法 -- reduce()
    ES6 -- 展开运算符
    Centos7 + Oracel 18c
    Mysql 查询返回大量数据导致内存溢出
    github的安装和使用
  • 原文地址:https://www.cnblogs.com/clrs97/p/12145060.html
Copyright © 2011-2022 走看看