loj517 计算几何瞎暴力(Trie树)

题目:

https://loj.ac/problem/517

分析:

操作4比较特殊,我们先来分析下操作4

操作4相当于需要一个数据结构,使得里面的数据有序(这有很多选择)

结合操作1,操作4的“排序”实际上指的是,将上一次排序之后加入的一些点,插入到这个数据结构中,ok,这也很中规中矩

于是我们需要一个数据结构和一个数组,数据结构存着有序的情况,数组存着后来插入的数,如果遇到了一个操作4,那么就把数组里的数一个一个插入到数据结构中

对于操作2,求区间和,也很中规中矩,很多有序的数据结构都可以支持区间和查询,对于另一部分的数组,也可以支持区间和查询

然后再看操作3,整体异或

我们先来考虑后面的数组如何整体异或:首先为了查询区间和,数组肯定要求前缀和,那么我们如何根据整体异或的修改来改变前缀和呢?其实很简单,我们不要单纯的前缀和,我们记下每一个二进制位(0,1)的前缀和,那么根据当前的整体异或值xortag的各个位的0/1情况,我们就知道贡献是多少。

然后考虑“数据结构”,很自然根据异或就想到Trie树,我们来看看Trie树如何满足所有的操作

操作1:不关Trie树的事

操作2:求区间和->求前缀和,注意到一个性质,那就是本题Trie树所管辖的下标区间,数字都是有序的,所以这里相当于求Trie树中最小的x个数的和;只需要记录每个点下面数字的个数size就行了;

操作3:对于一个整体标记tag,我们可以直接代数运算,这里主要提一下对于当前一个存在的tag,我们如何进行操作2的询问。我们将tag的每一位分解在Trie树上走,如果某一位tag为1,那么其实相当于左儿子'0'比右儿子'1'大,只需要颠倒判断一下即可

操作4:将数组中的元素一个一个插入到Trie树种即可

时间复杂度O((n+m)logn*logA)

细节:

1、注意,对于一个操作3,我们实际上并不能直接修改Trie树的tag值,因为修改了tag值其实表示我们的Trie树在当前tag值下有序,而一次操作3,但没有经过操作4,我们的Trie树对应的位置是不一定有序的,那么怎么处理呢?可以分开保存两个标记,一个tag表示当前Trie树在异或tag意义下有序(即上个操作4后的结果),一个xortag表示当前真正的异或值,在Trie树中,我们查询的时候就根据tag来,get子树和的时候就根据xortag来;然后外面的数组就一直是xortag,遇到操作4就把xortag传给Trie树的tag

2、在Trie树中查找前x小的数字的和的时候,要注意这种情况:比如最小数字0出现了3次,我现在想求最小的前2个数字和,那么这个时候就需要特判

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=1e5,maxh=30;
  4 int xortag,n,m;
  5 struct trie
  6 {
  7     int ch[maxn*maxh][2];
  8     int sz[maxn*maxh];
  9     int sum[maxn*maxh][maxh];
 10     int root=0;
 11     int len=0;
 12     int tag=0;
 13     void insert(int x)
 14     {
 15         int u=root;
 16         for(int i=maxh-1;i>=0;--i)
 17         {
 18             int id=((x&(1<<i))>0);
 19             if(!ch[u][id]) ch[u][id]=++len;
 20             u=ch[u][id];
 21             ++sz[u];
 22             for(int j=0;j<maxh;++j)
 23                 if(x&(1<<j)) sum[u][j]++;
 24         }
 25     }
 26     long long getsum(int x)
 27     {
 28         long long ans=0;
 29         for(int i=0;i<maxh;++i)
 30             if(xortag&(1<<i)) ans+=(sz[x]-sum[x][i])*(1LL<<i);else ans+=sum[x][i]*(1LL<<i);
 31         return ans;
 32     }
 33     long long query(int x)
 34     {
 35         if(x==0) return 0;
 36         int u=root;
 37         long long ans=0;
 38         for(int i=maxh-1;i>=0;--i)
 39         {
 40             int l=0,r=1;
 41             if(tag&(1<<i)) swap(l,r);
 42             if(x<=sz[ch[u][l]]) u=ch[u][l];
 43             else
 44             {
 45                 ans+=getsum(ch[u][l]);
 46                 x-=sz[ch[u][l]];
 47                 u=ch[u][r];
 48             }
 49         }
 50         ans+=getsum(u)/sz[u]*x;
 51         return ans;
 52     }
 53     int getsize()
 54     {
 55         return sz[ch[root][0]]+sz[ch[root][1]];
 56     }
 57 }Trie;
 58 struct array
 59 {
 60     int a[maxn+50];
 61     int sum[maxn+50][maxh];
 62     int len=0;
 63     void insert(int x)
 64     {
 65         x^=xortag;
 66         a[++len]=x;
 67         for(int i=0;i<maxh;++i)
 68             sum[len][i]=sum[len-1][i]+((x&(1<<i))>0);
 69     }
 70     long long query(int x)
 71     {
 72         long long ans=0;
 73         for(int i=0;i<maxh;++i)
 74             if(xortag&(1<<i)) ans+=(x-sum[x][i])*(1LL<<i);else ans+=sum[x][i]*(1LL<<i);
 75         return ans;
 76     }
 77     void transfer()
 78     {
 79         Trie.tag=xortag;
 80         for(int i=1;i<=len;++i)
 81             Trie.insert(a[i]);
 82         len=0;
 83     }
 84 }Array;
 85 long long query(int x)
 86 {
 87     if(x<=Trie.getsize()) return Trie.query(x);
 88     else return Trie.query(Trie.getsize())+
 89         Array.query(x-Trie.getsize());
 90 }
 91 int main()
 92 {
 93     scanf("%d",&n);
 94     for(int i=1;i<=n;++i)
 95     {
 96         int x;
 97         scanf("%d",&x);
 98         Array.insert(x);
 99     }
100     scanf("%d",&m);
101     for(int i=1;i<=m;++i)
102     {
103         int op,x,y;
104         scanf("%d",&op);
105         if(op==1)
106         {
107             scanf("%d",&x);
108             Array.insert(x);
109         }
110         if(op==2)
111         {
112             scanf("%d%d",&x,&y);
113             printf("%lld\n",query(y)-query(x-1));
114         }
115         if(op==3)
116         {
117             scanf("%d",&x);
118             xortag^=x;
119         }
120         if(op==4) Array.transfer();
121     }
122     return 0;
123 }
View Code

 

posted @ 2017-07-06 20:30  Chellyutaha  阅读(636)  评论(0编辑  收藏  举报