zoukankan      html  css  js  c++  java
  • [CDQ分治][Treap][树状数组]Theresa与数据结构

    Description

    这是个复杂的世界。人类社会,自然界,还有地球之外的银河……
    每一天日出日落,人来人往,步履匆匆。究竟是为什么呢?那支配着一切的至高无上的法则又是否存在呢?Theresa知道,这个问题并不是一朝一夕就可以解答的,只有在仔细、深入的观察和思考以后,才有可能将所有支离破碎的线索联系起来,从而隐约窥见真实的答案。
    于是,Theresa经常思考生活中遇到的大大小小的问题。为什么港台出版的书籍里印刷的汉字她一个也不认识呢?为什么隔夜的白开水中富含一氧化二氢呢?为什么每年都有一段时间Gmail邮箱上不去呢?
    为了更加系统、科学地分析这些问题,Theresa决定向你求助。
    长话短说,Theresa想请你帮助她实现一个数据结构。这个数据结构的功能是在空间直角坐标系中维护一个点的集合,并支持以下三类操作:
    1. ADD x y z 加入一个新的点,点的坐标为(x, y, z)。
    2. QUERY x y z r 查询在正方体(x, y, z) - (x+r, y+r, z+r)内部的点的数目。
    3. CANCEL 撤销最近的一次ADD操作。
    其中x, y, z, r均为给出的整数。QUERY操作中,(x, y, z)为正方体的一个顶点的坐标,r为正方体的边长。在正方体边界上的点也算在正方体内部。
    这个问题可能过于困难,所以Theresa并不强迫你实现一个高效的数据结构。然而,你必须对每一次QUERY操作给出正确的答案。
     
     

    Input

    第一行包含一个整数N,表示最初的点集有N个点。
    接下来N行,每行包含三个整数xi、yi、zi,依次表示每个点的坐标。
    第N+2行包含一个整数Q,表示将有Q次操作。
    接下来Q行,每行表示一次操作,格式如题目描述。

    Output

    输出若干行,每行一个整数,依次表示每次查询操作的答案。
     

    Sample Input

    2
    1 2 3
    1 1 3
    7
    ADD 0 4 3
    QUERY 0 0 0 4
    ADD 1 1 5
    QUERY 1 1 2 3
    QUERY 0 2 2 1
    CANCEL
    QUERY 1 1 2 3

    Sample Output

    3
    3
    1
    2
    样例解释:
    第1次查询正方体(0, 0, 0) - (4, 4, 4),内部包含点(1, 2, 3),(1, 1, 3),(0, 4, 3)。
    第2次查询正方体(1, 1, 2) - (4, 4, 5),内部包含点(1, 2, 3),(1, 1, 3),(1, 1, 5)。
    第3次查询正方体(0, 2, 2) - (1, 3, 3),内部包含点(1, 2, 3)。
    第4次查询正方体(1, 1, 2) - (4, 4, 5),内部包含点(1, 2, 3),(1, 1, 3)。
     
     

    Data Constraint

    对于10%的数据:1 ≤ N, Q ≤ 1 000。
    此外10%的数据:0 ≤ x, y, z ≤ 100,1 ≤ r ≤ 100。
    此外30%的数据:没有ADD操作和CANCEL操作。
    此外20%的数据:没有CANCEL操作。
    以上70%的数据:1 ≤ N, Q ≤ 50 000。
    对于100%的数据:1 ≤ N + Q ≤ 100 000, 0 ≤ x, y, z, r ≤ 10^7。r 为正整数。   所有的CANCEL操作均为有效操作。不同的点的坐标可能重合。

    分析

    这题是个四维偏序问题。

    时间那维我们用CDQ分治解决

    x我们可以排序离散化

    y用树状数组,z用Treap(没敢用Splay常数太大233)

    那么这题是一个CDQ分治套树套树

    (写LowerBound气死了,忘记在上界加个1)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cstring>
    #define rep(i,a,b) for (i=a;i<=b;i++)
    #define lowbit(x) x&-x
    const int N=100005;
    using namespace std;
    struct Node {
        int l,r,key,mak,dat,sum;
    }t[50*N];
    int tcnt;
    struct Point {
        int x,y,z;
    }stk[N];
    struct Query {
        Point p;
        int r,t,id;
    }q[N],a[2*N];
    int qcnt;
    int rt[N];
    int sy,sq,sh,n,m,top;
    int ans[N],y[N];
    //Treap
    void Update(int x) {
        t[x].sum=t[x].dat+t[t[x].l].sum+t[t[x].r].sum;
    }
    
    void Left_Rotate(int &x) {
        int s=t[x].r;
        t[x].r=t[s].l;t[s].l=x;
        Update(x);Update(s);
        x=s;
    }
    
    void Right_Rotate(int &x) {
        int s=t[x].l;
        t[x].l=t[s].r;t[s].r=x;
        Update(x);Update(s);
        x=s;
    }
    
    void Insert(int &x,int mak,int dat) {
        if (!x) {
            x=++tcnt;t[x].l=t[x].r=0;t[x].mak=mak;t[x].sum=t[x].dat=dat;t[x].key=rand();
            return;
        }
        if (mak<t[x].mak) {
            Insert(t[x].l,mak,dat);
            if (t[t[x].l].key>t[x].key) Right_Rotate(x);
        }
        else {
            Insert(t[x].r,mak,dat);
            if (t[t[x].r].key>t[x].key) Left_Rotate(x);
        }
        Update(x);
    }
    
    int Get_Suk(int x,int mak) {
        if (!x)    return 0;
        if (mak<t[x].mak) return Get_Suk(t[x].l,mak);
        return Get_Suk(t[x].r,mak)+t[x].dat+t[t[x].l].sum;
    }
    //Treearray
    void Add(int x,int z,int dat) {
        for (int i=x;i<=sy+1;i+=lowbit(i)) Insert(rt[i],z,dat);
    }
    
    int Get_Sum(int x,int z,int r) {
        int ans=0;
        for (int i=x;i;i-=lowbit(i)) ans+=Get_Suk(rt[i],z+r)-Get_Suk(rt[i],z-1);
        return ans;
    }
    
    void Init() {
        int i;
        char s[20];
        scanf("%d",&n);
        rep(i,1,n) {
            sq++;
            scanf("%d%d%d",&q[sq].p.x,&q[sq].p.y,&q[sq].p.z);
            q[sq].id=sq;q[sq].t=1;
        }
        scanf("%d",&m);
        rep(i,1,m) {
            scanf("%s",&s);
            if (s[0]=='A') {
                sq++;
                scanf("%d%d%d",&q[sq].p.x,&q[sq].p.y,&q[sq].p.z);
                q[sq].id=sq;q[sq].t=1;
                stk[++top]=q[sq].p;
            }
            if (s[0]=='C') {
                sq++;
                q[sq].p=stk[top--];
                
                q[sq].id=sq;q[sq].t=-1;    
            }
            if (s[0]=='Q') {
                sq++;
                scanf("%d%d%d%d",&q[sq].p.x,&q[sq].p.y,&q[sq].p.z,&q[sq].r);
                q[sq].id=sq;q[sq].t=0;
            }
        }
    }
    
    bool Cmp(Query a,Query b) {
        return a.p.x<b.p.x||a.p.x==b.p.x&&a.t<b.t;
    }
    
    int Lower_Bound(int l,int r,int x) {
        if (x<y[1]) return 1;
        while (l<r) {
            int mid=l+r+1>>1;
            if (y[mid]>x) r=mid-1; else l=mid;
        }
        return l+1;
    }
    
    void Fix() {
        int i;
        sort(a+1,a+sh+1,Cmp);
        sy=0;
        rep(i,1,sh)
        if (a[i].t<2) y[++sy]=a[i].p.y;
        sort(y+1,y+sy+1);
        sy=unique(y+1,y+sy+1)-(y+1);
        rep(i,1,sy+1) rt[i]=0;tcnt=0;
        rep(i,1,sh) {
            if (a[i].t<2)
            Add(Lower_Bound(1,sy,a[i].p.y),a[i].p.z,a[i].t);
            else {
                int l=Lower_Bound(1,sy,a[i].p.y-1),r=Lower_Bound(1,sy,a[i].p.y+a[i].r);
                if (l==r) continue;
                ans[a[i].id]+=(Get_Sum(r,a[i].p.z,a[i].r)-Get_Sum(l,a[i].p.z,a[i].r))*(a[i].t-3); 
            }
        }
    }
    bool In(Point a,Point b,int r) {
        return a.x>=b.x&&a.y>=b.y&&a.z>=b.z&&a.x<=b.x+r&&a.y<=b.y+r&&a.z<=b.z+r;
    }
    
    void Work(int l,int r) {
        int so=0,sa=0,i,j;
        rep(i,l,r) if (!q[i].t) sa++; else so++;
        if (!sa||!so) return;
        if (r-l+1<=400) {
            rep(i,l,r-1)
            rep(j,i+1,r)
            if (!q[j].t&&In(q[i].p,q[j].p,q[j].r)) ans[q[j].id]+=q[i].t;
            return;
        }
        int mid=l+r>>1;
        if (l==1&&r==sq) mid=n;
        Work(l,mid);
        Work(mid+1,r);
        sh=0;
        rep(i,l,mid) if (q[i].t!=0) a[++sh]=q[i];
        int hs=sh;
        rep(i,mid+1,r)
        if (!q[i].t) {
            a[++sh]=q[i];a[sh].p.x--;a[sh].t=2;
            a[++sh]=q[i];a[sh].p.x+=q[i].r;a[sh].t=4;
        }
        if (hs&&sh>hs) Fix();
    }
    
    void Print() {
        int i;
        rep(i,1,sq)
        if (!q[i].t) printf("%d\n",ans[q[i].id]);
    }
    
    int main() {
        Init();
        Work(1,sq);
        Print();
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    模式识别之检索---Bag of visual word(词袋模型)
    模式识别之knn---KNN(k-nearest neighbor algorithm)--从原理到实现
    目标跟踪之meanshift---meanshift2
    图像处理之增强---图像模糊检测
    模式识别之非参数估计---非参估计中的核函数
    haproxy文章
    nginx 有关防盗链的设置
    haproxy 关闭ssl3
    navicat 在写存储过程的时候总是说语法错误
    开源的报表系统easyreport的部署
  • 原文地址:https://www.cnblogs.com/mastervan/p/9404416.html
Copyright © 2011-2022 走看看