zoukankan      html  css  js  c++  java
  • 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
    ",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
  • 相关阅读:
    IOS Array 排序方法
    一个制作Xcode5插件的模板
    UITableViewCell滑动删除及移动
    strong weak
    越狱检测/越狱检测绕过
    XML在线转化为JSON
    KissXML类库的使用方法
    iOS perform action after period of inactivity (no user interaction)
    Objective-C在ARC下结合GCD的单例模式和宏模版
    Xcode5 如何添加一个Github/Repository 并且Checkout
  • 原文地址:https://www.cnblogs.com/wmrv587/p/7128225.html
Copyright © 2011-2022 走看看