hdu 5126 cdq+Treap+BIT

这题说的是给了三维空间然后操作 寻求在 x1,y1,z1    x2, y2, z2; (x1<x2, y1<y2,z1<z2) 计算出在 以这两个端点为右下和左上端点的方体内的点的个数。CDQ 分治第一次听说,

在一个方体内使用容斥原理,然后不断的将剩下的点分成两个部分,然后这样不断地下去,对于每个部分在进行一次CDQ然后,再使用BIT求解,这样我们可以看看他这神奇的CDQ,他先是这样的,第一次CDQ先对在区间内的点进行x轴排序,排完后然后将这些点按照y轴进行合并,这样做的好处是想想二分后的一部分在一侧另一部分只会用到前一部分的,用这种方法可以让后面的所有的点都得到他被包含的查询内、

cdq套cdq套bit

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn=50005;
struct point{
   int x,y,z,delt,qnum,kind;
   point(){}
   point(int a,int b, int c,int d,int e,int f){
     this->x=a;this->y=b;this->z=c;this->delt=d;
     this->qnum=e; this->kind=f;
   }
}star[maxn*8],start3[maxn*8];
int Z[maxn*8],tot,qnum,ans[maxn*8],N,C[maxn*8];
bool use[maxn*8];
int lowbit(int x){ return x&(-x);   }
void aDD(int loc, int val){
      while(loc<=N){
        C[loc]+=val;
        loc+=lowbit(loc);
      }
}
int sum(int loc){
    int s=0;
    while(loc>0){
        s+=C[loc];
        loc-=lowbit(loc);
    }
    return s;
}
void add(int x,int y,int z,int delt,int qnum,int kind ){
     star[tot]=point(x,y,z,delt,qnum,kind);
     Z[tot]=z;++tot;
}
void scatter(){
    sort(Z,Z+tot);
    N=unique(Z,Z+tot)-Z;
    for(int i=0; i<tot; ++i)
         star[i].z=lower_bound(Z,Z+N,star[i].z)-Z+1;
}
bool cmp1(point A, point B){
  return A.x<B.x||(A.x==B.x&&A.qnum<B.qnum);
}
bool cmp2(point A, point B){
   return A.y<B.y||(A.y==B.y&&A.qnum<B.qnum);
}
void CDQ2(int L, int R){
    if(L>=R) return ;
    int mid=(R+L)>>1;
    CDQ2(L,mid);
    CDQ2(mid+1,R);
    int j=L;
    for(int i=mid+1;i<=R; ++i){

         for( ;j<=mid && ( start3[j].y <= start3[i].y ) ; ++j )
            if(start3[j].kind==0){
             aDD(start3[j].z,start3[j].delt);
         }
         ans[start3[i].qnum]+=sum(start3[i].z)*start3[i].delt;
    }
    for(int i=L; i<j; ++i)
        if(start3[i].kind==0)
            aDD(start3[i].z,-start3[i].delt);
    inplace_merge(start3+L,start3+mid+1,start3+R+1,cmp2);
}
void CDQ1(int L, int R){
    if(L>=R) return ;
    int mid =(L+R)>>1;
    CDQ1(L, mid );
    CDQ1(mid+1,R);
    int num=0;
    for(int i=L; i<=mid; ++i)
        if(star[i].kind==0)
         start3[num++]=star[i];
    for(int i=mid+1;i<=R; ++i)
         if(star[i].kind==1)
          start3[num++]=star[i];
    sort(start3,start3+num,cmp1);
    CDQ2(0,num-1);
}
int main()
{
   int cas;
   scanf("%d",&cas);
   memset(use,false,sizeof(use));
   memset(ans,0,sizeof(ans));
   while(cas--){
       int Q ;
       tot=qnum=0;
       scanf("%d",&Q);
       for(int i=0; i<Q; ++i){
           int A;
           scanf("%d",&A);
           if(A==1){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
               add( x, y, z, 1, qnum, 0);qnum++;
           }else{
                int x1,y1,z1,x2,y2,z2;
                use[qnum]=true;
                scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
                add(x1-1,y1-1,z1-1,-1,qnum,1);
                add(x1-1,y1-1,z2  , 1,qnum,1);
                add(x1-1,y2  ,z1-1, 1,qnum,1);
                add(x1-1,y2  ,z2  ,-1,qnum,1);
                add(x2  ,y2  ,z1-1,-1,qnum,1);
                add(x2  ,y2  ,z2  , 1,qnum,1);
                add(x2  ,y1-1,z1-1, 1,qnum,1);
                add(x2  ,y1-1,  z2,-1,qnum,1);
                qnum++;
            }

       }
       scatter();
       CDQ1(0,tot-1);
       for(int i=0; i<qnum; ++i){

        if(use[i]==true) printf("%d\n",ans[i]);
           use[i]=false; ans[i]=0;
        }
   }

    return 0;
}

这里有一个方法使用cdq里面套了一个BIT 然后套 了一个Treap 使用cdq分治,然后离散了x 然后在BiT上放上棵Treap,通过Treap 去找到对应的个数

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <cstdlib>
using namespace std;
const int maxn=50000+10;
struct Node{
   Node *ch[2];
   int r;
   int y;
   int spoint;
   int loc;
   void maintain(){
         spoint=loc;
         if(ch[0]!=NULL) spoint+=ch[0]->spoint;
         if(ch[1]!=NULL) spoint+=ch[1]->spoint;
   }
   Node(int v):y(v){ r=rand(); spoint=1; loc=1; ch[0]=ch[1]=NULL; }
   int cmp(int x){
       if(x==y) return -1;
       return x<y?0:1;
   }
};
Node *T[maxn*3];
int now[maxn*3],Time;
void removetree(Node *&o){
    if(o->ch[0]!=NULL) removetree(o->ch[0]);
    if(o->ch[1]!=NULL) removetree(o->ch[1]);
    delete o;
    o=NULL;
}
void rotate(Node *&o, int d){
  Node *k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o;
  o->maintain(); k->maintain(); o=k;
}
void insert(Node *&o, int y){
    if(o==NULL){
       o=new Node(y);
    }else{
       int d=o->cmp(y);
       if(d==-1){
          o->loc++;
       }else{
          insert(o->ch[d],y);
          if( o->ch[d]->r > o->r ) rotate(o,d^1);
       }
    }
    o->maintain();
}
struct point{
     int x1,x2,y1,y2,z;
     int op,q;
     point(int x1=0,int y1=0,int x2=0, int y2=0,int z=0, int op=0, int q=0){
         this->x1=x1;this->y1=y1; this->x2=x2;this->y2=y2; this->z=z;
         this->op=op; this->q=q;

     }
}P[maxn*3],s1[maxn*3];
int cntx[maxn*3],ans[maxn],point_cnt,x_cnt;
bool vis[maxn];
bool cmp(point A, point B){
    if(A.z!=B.z)return A.z<B.z;
    return A.q<B.q;
}
int lowbit(int x){
  return x&(-x);
}
void add(int loc, int y){
      while(loc<=x_cnt){
         if( now[ loc ] != Time ){
                if(T[loc]!=NULL)removetree(T[loc]);
                T[loc]=NULL;
                now[loc]=Time;
         }
         insert(T[loc],y);
         loc+=lowbit(loc);
      }
}
int search(Node *&o , int y){
   if(o==NULL) return 0;
   if(y<o->y) return search(o->ch[0],y);
   else {
     int a=search(o->ch[1],y);
     if(o->ch[0]!=NULL)
        a+=o->ch[0]->spoint;
     a+=o->loc;
     return a;
   }
}
int sum(int loc, int y){
    int ans=0;
    while(loc>0){
        if(now[loc]==Time) ans+=search(T[loc],y);
        loc-=lowbit(loc);
    }
    return ans;
}
void cdq_fz(int L, int R){
      if(L>=R) return ;
      int mid=(L+R)/2;
      int e=0;
      cdq_fz(     L, mid );
      cdq_fz( mid+1,   R );
      for(int i=L; i<=mid; ++i)
        if(P[i].q==0) s1[e++]=P[i];
      for(int i=mid+1; i<=R; ++i)
        if(P[i].q!=0) s1[e++]=P[i];
       sort(s1,s1+e,cmp);
       Time++;
       for(int i=0; i<e; ++i)
        if(s1[i].q==0){
             add(s1[i].x2,s1[i].y2);
        }else{
             ans[s1[i].q]+=s1[i].op*sum(s1[i].x2,   s1[i].y2);
             ans[s1[i].q]-=s1[i].op*sum(s1[i].x1,   s1[i].y2);
             ans[s1[i].q]-=s1[i].op*sum(s1[i].x2,   s1[i].y1);
             ans[s1[i].q]+=s1[i].op*sum(s1[i].x1,   s1[i].y1);
        }
}
void solve(){
    int N;
     scanf("%d",&N);
     for(int cc=1; cc<=N; ++cc){
         int op,x1,x2,y1,y2,z1,z2;
         scanf("%d",&op);
         if(op==1){
             scanf("%d%d%d",&x1,&y1,&z1);
             P[point_cnt++]=point(x1,y1,x1,y1,z1,1,0);
             cntx[x_cnt++]=x1;
             vis[cc]=false;
         }else{
             scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
             cntx[x_cnt++]=x1-1;
             cntx[x_cnt++]=x2;
             P[point_cnt++]=point(x1-1,y1-1,x2,y2,  z2, 1,cc);
             P[point_cnt++]=point(x1-1,y1-1,x2,y2,z1-1,-1,cc);
             vis[cc]=true;
         }
     }
     sort(cntx,cntx+x_cnt);
     x_cnt=unique(cntx,cntx+x_cnt)-cntx;
     for(int i=0 ; i<point_cnt ; ++i ){
        if(P[i].q!=0)
        P[i].x1=lower_bound(cntx,cntx+x_cnt,  P[i].x1)-cntx+1;
        P[i].x2=lower_bound(cntx,cntx+x_cnt,  P[i].x2)-cntx+1;
    }
     cdq_fz(0,point_cnt-1);
     for( int i=1; i<=N; ++i )
         if( vis[i] ) printf("%d\n",ans[i]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
         memset(ans,0,sizeof(ans));
         memset(now,0,sizeof(now));
         x_cnt = point_cnt=0;
         Time=1;
         solve();
    }
    return 0;
}

时间: 2025-01-03 18:45:56

hdu 5126 cdq+Treap+BIT的相关文章

HDU 5126(stars)四维偏序,cdq分治

题意:给两种操作,进行5万次.操作一:加入一个三维序偶(a,b,c)到集合S里:第二种操作,给两个三维序偶(a1,b1,c1)和(a2,b2,c2),问当前S里有多少个序偶(a,b,c)满足a1<=a<=a2, b1<=b<=b2, c1<=c<=c2.题目保证了a1<=a2,b1<=b2,c1<=c2.所有数在[1,1e9]内 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5126 解法:将操作编号也加入到

HDU 5126 stars cdq分治+树状数组

题目链接:点击打开链接 题意: T个case n个操作 1. (x,y,z) 在三维平面的点上增加1 2.询问区间范围内的权值和. 思路: cdq分治套cdq分治,然后套树状数组即可.. #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #include <string.h> #inclu

HDU - 5126 stars (CDQ分治)

题目大意:一共有Q(1<=Q<=50000)组操作,操作分为两种: 1.在x,y,z处添加一颗星星 2.询问以(x1,y1,z1)与(x2,y2,z2)为左上和右下顶点的矩形之间的星星数 所有坐标取值范围均为[1,1e9] 思路:由于坐标取值范围太大(即使离散化后也很大),3维的数组肯定开不下,所以只能另辟蹊径. 解法一(两重CDQ+树状数组,需将z坐标离散化): 1)将每个查询操作拆分为8个(容斥),将所有操作放入一个数组qr中 2)将所有操作按时间排序(其实不用,因为读入的顺序就是按时间排

HDU - 5126: stars (求立方体内点数 CDQ套CDQ)

题意:现在给定空空的三维平面,有加点操作和询问立方体点数. 思路:考虑CDQ套CDQ.复杂度是O(NlogN*logN*logN),可以过此题. 具体的,这是一个四维偏序问题,4维分别是(times,x,y,z):我们知道cdq可以求出t<=T,x=X,y<=Y,在套一层就可以z<=Z了.那么一个立方体,我们拆为8个点来容斥. 然后现在的问题就是,求出(0,0,0)到(x,y,z)的点数. 第一维T已经默认排序了,我们先对X分治. 把所有问题分成两块,并且把左边这块标记o=-1,右边的标

hdu 5493 Queue treap实现将元素快速插入到第i个位置

input T 1<=T<=1000 n 1<=n<=100000 h1 k1 h2 k2 ... ... hn kn 1<=hi<=1e9  0<=ki<=n-1 sum(n)<=1e6 hi!=hj(i!=j) output hi指第i个人的身高,ki指这个人前面或者后面比他高的人数 Case #cas: 输出可能的最小序列,没有输出impossible 做法:将所有人按身高排序,从高到低插入数组中,则插入到第i个人时,数组里所有人都比他高,用tr

HDU 5618:Jam&#39;s problem again(CDQ分治+树状数组处理三维偏序)

http://acm.hdu.edu.cn/showproblem.php?pid=5618 题意:-- 思路:和NEUOJ那题一样的.重新写了遍理解了一下,算作处理三维偏序的模板了. 1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 using namespace std; 6 #define INF 0x3f3f3f3f 7 #d

HDU 4006 求第k大数 treap

裸题,瞬秒.. #include <stdio.h> #include <iostream> #include <algorithm> #include <math.h> #include <vector> #include <set> #include <map> #include <queue> using namespace std; #define L(id) tree[id].ch[0] #defin

HDU 3726 Graph and Queries treap树

题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; struct Node { Node *ch[2]; int r; int v; int s; Node(int v): v(v) { ch[0] = ch[1] = NULL; r = rand(); s

BZOJ3262陌上花开 CDQ分治_BIT+Treap

三个属性, 第一个属性用cdq分治处理, 以第一个属性为关键字从小到大排序, 那么考虑一朵花的等级, 只需考虑排在其前面的花的其他属性(特殊情况是有相同的花,根据题意,对一段相同的花,以排在最后的一朵花的答案为准), 第二三维可以用树状数组加Treap解决, 以每朵花第二属性数值作为位置(因为最大属性k < 2e5, 可以不用离散化, 直接用属性的数值对应树状数组中的下标), 树状数组的每个节点建一颗Treap, 这颗Treap里存的是相应区间里的花的第三个属性, 询问时类似于树状数组求前缀和,