jzoj3304. 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操作均为有效操作。不同的点的坐标可能重合。

10~70%

瞎写
反正这题不需要

100%

显然是四维偏序。。。
(时间+x+y+z)

根据时间排序,之后把询问拆开,cdq分治去掉x
然后y和z直接带修主席树。。。

(其实不用拆成四维偏序,只拆x,就只用拆成两个询问)
我考试时像SB一样把一个询问拆成了八个然后T到飞起

带修主席树

(似乎二维线段树的常数太大了)

实际跟主席树没有太大关系,就是树状数组套线段树
(没有像主席树那样共用节点)

具体来说,普通主席树一棵树维护的是一个前缀,所以如果要修改就要 O(nlog) O ( n log )
然而带修主席树用树状数组的思想,每棵树维护的是树状数组中对应的一个区间
所以一次只用修改 O(log) O ( log ) 棵线段树,所以兹磁 O(log2) O ( log 2 ) 修改&查询

没了。

code

不算特别难写。。。

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
using namespace std;

struct AA{
    int type,x,y,y2,z,z2,s,id,T;
}a[200001],A[200001],b[100001];
int n,i,j,k,l,Q,x,y,z,r,len,N,sum,sum2,Len1,Len2,X;
char S[10];
int ans[100001];
int root[200001];
int tr[12225000][3];
struct C{
    int x,y,z;
}c[1600001];

void New(int t,int x)
{
    if (!tr[t][x])
    tr[t][x]=++N;
}

inline bool cmp(AA a,AA b)
{
    return a.x>b.x || a.x==b.x && a.T<b.T;
}

inline bool cmp1(C a,C b)
{
    return a.x<b.x;
}

void change(int t,int l,int r,int x,int s)
{
    int mid=(l+r)/2;

    tr[t][2]+=s;
    if (l==r) return;

    if (x<=mid)
    {
        New(t,0);
        change(tr[t][0],l,mid,x,s);
    }
    else
    {
        New(t,1);
        change(tr[t][1],mid+1,r,x,s);
    }
}

void find(int t,int l,int r,int x,int y)
{
    int mid=(l+r)/2;

    if (x<=l && r<=y)
    {
        sum+=tr[t][2];
        return;
    }

    if (x<=mid && tr[t][0])
    find(tr[t][0],l,mid,x,y);
    if (mid<y  && tr[t][1])
    find(tr[t][1],mid+1,r,x,y);
}

int low(int x)
{
    return x&(-x);
}

void dg(int l,int r)
{
    int i,j,k,mid=(l+r)/2;

    if (l<r)
    {
        dg(l,mid);
        dg(mid+1,r);
    }

    i=0; //¹é²¢ÅÅÐò 
    j=l;
    k=mid+1;
    while (j<=mid || k<=r)
    {
        i++;
        if (k>r || (j<=mid && (a[j].x>a[k].x || a[j].x==a[k].x && a[j].T<a[k].T)))
        A[i]=a[j++];
        else
        A[i]=a[k++];
    }
    fo(i,1,r-l+1)
    a[i+l-1]=A[i];

//  sort(a+l,a+r+1,cmp);

    X++;

    N=Len1;
    fo(i,l,r)
    if (!a[i].type)
    {
        if (a[i].id<=mid)
        {
            j=a[i].y;
            while (j<=Len1)
            {
//              if (!root[j])
//              root[j]=++N;

//              change(root[j],1,Len2,a[i].z,a[i].s);

                if (root[j]!=X)
                {
                    root[j]=X;
                    tr[j][0]=0;
                    tr[j][1]=0;
                    tr[j][2]=0;
                }

                change(j,1,Len2,a[i].z,a[i].s);
                j+=low(j);
            }
        }
    }
    else
    {
        if (a[i].id>mid)
        {
            sum=0;
            j=a[i].y-1;
            while (j)
            {
//              if (root[j])
//              find(root[j],1,Len2,a[i].z,Len2);

                if (root[j]==X)
                find(j,1,Len2,a[i].z,a[i].z2);
                j-=low(j);
            }

            sum2=sum;
            sum=0;
            j=a[i].y2;
            while (j)
            {
//              if (root[j])
//              find(root[j],1,Len2,a[i].z,Len2);

                if (root[j]==X)
                find(j,1,Len2,a[i].z,a[i].z2);
                j-=low(j);
            }

            sum-=sum2;
            ans[a[i].s]+=sum*a[i].type;
        }
    }

    fo(i,Len1+1,N)
    {
        tr[i][0]=0;
        tr[i][1]=0;
        tr[i][2]=0;
    }
//  fo(i,l,r)
//  if (!a[i].type && a[i].id<=mid)
//  {
//      j=a[i].y;
//      while (j<=Len1)
//      {
//          if (root[j])
//          root[j]=0;
//          else break;
//          j+=low(j);
//      }
//  }
}

void add(int x,int y,int y2,int z,int z2,int type,int s,int id,int T)
{
    len++;
    a[len].x=x;
    a[len].y=y;
    a[len].y2=y2;
    a[len].z=z;
    a[len].z2=z2;
    a[len].type=type;
    a[len].s=s;
    a[len].id=len;
    a[len].T=T;
}

int main()
{
//  freopen("theresa14.in","r",stdin);

    scanf("%d",&n);
    fo(i,1,n)
    {
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);

        a[i].type=0;
        a[i].s=1;
        a[i].id=i;
    }
    len=n;

    j=0;k=0;
    for (scanf("%d",&Q); Q; Q--)
    {
        scanf("%s",S);

        if (S[0]=='A')
        {
            scanf("%d%d%d",&x,&y,&z);

            add(x,y,0,z,0,0,1,len,0);

            j++;
            b[j].x=x;
            b[j].y=y;
            b[j].z=z;
        }
        else
        if (S[0]=='Q')
        {
            k++;
            scanf("%d%d%d%d",&x,&y,&z,&r);

            add(x,y,y+r,z,z+r,1,k,len,1);
            add(x+r+1,y,y+r,z,z+r,-1,k,len,1);
        }
        else
        if (S[0]=='C')
        {
            add(b[j].x,b[j].y,0,b[j].z,0,0,-1,len,0);
            j--;
        }
    }

    fo(i,1,len)
    {
        c[i].x=a[i].y;
        c[i].y=i;
        c[i].z=1;
    }
    fo(i,1,len)
    {
        c[i+len].x=a[i].y2;
        c[i+len].y=i;
        c[i+len].z=2;
    }
    sort(c+1,c+len+len+1,cmp1);
    j=0;
    fo(i,1,len+len)
    {
        if (i==1 || c[i].x!=c[i-1].x)
        j++;
        if (c[i].z==1)
        a[c[i].y].y=j;
        else
        a[c[i].y].y2=j;
    }
    Len1=j;

    fo(i,1,len)
    {
        c[i].x=a[i].z;
        c[i].y=i;
        c[i].z=1;
    }
    fo(i,1,len)
    {
        c[i+len].x=a[i].z2;
        c[i+len].y=i;
        c[i+len].z=2;
    }
    sort(c+1,c+len+len+1,cmp1);
    j=0;
    fo(i,1,len+len)
    {
        if (i==1 || c[i].x!=c[i-1].x)
        j++;
        if (c[i].z==1)
        a[c[i].y].z=j;
        else
        a[c[i].y].z2=j;
    }
    Len2=j;

//  fo(i,1,len) cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].y2<<" "<<a[i].z<<" "<<a[i].z2<<" "<<a[i].type<<" "<<a[i].s<<" "<<a[i].id<<" "<<a[i].T<<endl;

    X=0;
    dg(1,len);

    fo(i,1,k)
    printf("%d\n",ans[i]);
}

注意事项

本题出题人成心卡时间,所以有几点可供参考
①cdq时用归并排序O(n)合并
②每棵线段树的根先开好,之后记录下时间,就不用全部一起清空了
③O2+register+读入输出优化+看脸

其它

据说一氧化二氢有剧毒(滑稽)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值