[cf1515H]Phoenix and Bits

记$V=2^{20}-1$,即值域范围,也可以作为"全集"

显然与$a_{i}$的顺序无关,对所有$a_{i}$维护一棵trie树

关于如何维护这棵trie树,考虑使用分裂+合并的方式,即:1.分裂出区间对应的trie树;2.操作分裂出的trie树;3.合并分裂出的tire树和原trie树

(关于时间复杂度后面会进行统一分析,暂时不需要考虑)

对于分裂(第1步),使用类似线段树查询的方法

对于合并(第3步),使用类似线段树合并的方法(即在其中一个子树为空时直接选择另一个子树)

对于操作(第2步),对不同的操作类型分类讨论——

查询操作:维护子树大小(子树内数值数量),直接输出即可

与操作:将其转化为异或$V$、或$x\oplus V$、异或$V$,那么只需要考虑异或和或操作即可

异或操作:直接在根节点上打懒标记,对于区间$[l,r]$的懒标记$tag$仅考虑$tag\and (r-l)$的结果,因此在下传标记时,若$tag\and \frac{r-l+1}{2}$非0则交换$[l,r]$的左右儿子

或操作:递归所有节点,当递归到区间$[l,r]$时,若$x\and \frac{r-l+1}{2}$非0则在$[l,r]$的左子树上打异或$\frac{r-l+1}{2}$的懒标记并合并$[l,r]$的左右子树(其中$x$为操作权值),再做如下剪枝——

维护子树与(子树内所有数值的与)和子树或,设当前子树两者分别为$v_{1}$和$v_{2}$,若$x\and (v_{1}\oplus v_{2}\oplus V)=x$(即子树内所有权值在$x$为1的位上都相同)则直接打上异或$x\and (v_{1}\oplus V)$的懒标记即可

("在$[l,r]$的左子树上打异或$\frac{r-l+1}{2}$的懒标记"的实际目的是维护子树与和子树或)

下面,来分析时间复杂度:

定义节点$x$的势能为$1+\log V+(v_{1}\oplus v_{2})$中1的个数(其中$v_{1}$和$v_{2}$为子树与和子树或,后者即$x$子树中仍未完全相同的位数),分别考虑这些操作的均摊复杂度——

分裂新建$o(\log V)$个节点,一个节点的势能为$o(\log V)$,即$o(\log^{2}V)$

合并递归过程中,若继续递归,即会合并两个节点,合并后势能减少$o(1)$,即均摊复杂度为$o(1)$

异或(打懒标记)不影响势能,即均摊复杂度为$o(1)$

或操作递归过程中,若不满足剪枝,必然会使得$v_{1}\oplus v_{2}$中1的个数减少1个,即均摊复杂度为$o(1)$

另外,势能和的范围显然也是​$o(n\log^{2}V)$

综上所述,总均摊复杂度为$o(n\log^{2}V)$,可以通过

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 8000005
  4 #define V ((1<<20)-1)
  5 #define mid (l+r>>1)
  6 int V_trie,rt,n,m,p,x,y,z,ls[N],rs[N],sz[N],And[N],Or[N],tag[N];
  7 int New(){
  8     int k=++V_trie;
  9     And[k]=V;
 10     return k;
 11 }
 12 void upd_xor(int k,int l,int r,int x){
 13     if (!k)return;
 14     tag[k]^=x;
 15     int p=((And[k]&(x^V))|((Or[k]^V)&x));
 16     Or[k]=((Or[k]&(x^V))|((And[k]^V)&x));
 17     And[k]=p;
 18 }
 19 void up(int k){
 20     sz[k]=sz[ls[k]]+sz[rs[k]];
 21     And[k]=(And[ls[k]]&And[rs[k]]);
 22     Or[k]=(Or[ls[k]]|Or[rs[k]]);
 23 }
 24 void down(int k,int l,int r){
 25     if (tag[k]&((r-l+1)>>1))swap(ls[k],rs[k]);
 26     upd_xor(ls[k],l,mid,tag[k]);
 27     upd_xor(rs[k],mid+1,r,tag[k]);
 28     tag[k]=0;
 29 }
 30 void add(int &k,int l,int r,int x){
 31     if (!k)k=New();
 32     if (l==r){
 33         sz[k]=1,And[k]=Or[k]=x;
 34         return;
 35     }
 36     if (x<=mid)add(ls[k],l,mid,x);
 37     else add(rs[k],mid+1,r,x);
 38     up(k);
 39 }
 40 int split(int &k,int l,int r,int x,int y){
 41     if ((!k)||(l>y)||(x>r))return 0;
 42     if ((x<=l)&&(r<=y)){
 43         int p=k;
 44         k=0;
 45         return p;
 46     }
 47     down(k,l,r);
 48     int kk=New();
 49     ls[kk]=split(ls[k],l,mid,x,y);
 50     rs[kk]=split(rs[k],mid+1,r,x,y);
 51     up(k),up(kk);
 52     return kk;
 53 }
 54 void merge(int &k1,int k2,int l,int r){
 55     if ((!k1)||(!k2)){
 56         k1+=k2;
 57         return;
 58     }
 59     if (l==r){
 60         sz[k1]=max(sz[k1],sz[k2]);
 61         And[k1]&=And[k2];
 62         Or[k1]|=Or[k2];
 63         return;
 64     }
 65     down(k1,l,r),down(k2,l,r);
 66     merge(ls[k1],ls[k2],l,mid);
 67     merge(rs[k1],rs[k2],mid+1,r);
 68     up(k1);
 69 }
 70 void upd_or(int k,int l,int r,int x){
 71     if (!k)return;
 72     if ((x&(And[k]^Or[k]^V))==x){
 73         upd_xor(k,l,r,(x&(And[k]^V)));
 74         return;
 75     }
 76     down(k,l,r);
 77     if (x&((r-l+1)>>1)){
 78         upd_xor(ls[k],l,mid,((r-l+1)>>1));
 79         merge(rs[k],ls[k],mid+1,r);
 80         ls[k]=0;
 81     }
 82     upd_or(ls[k],l,mid,x);
 83     upd_or(rs[k],mid+1,r,x);
 84     up(k);
 85 }
 86 int main(){
 87     scanf("%d%d",&n,&m);
 88     And[0]=V;
 89     for(int i=1;i<=n;i++){
 90         scanf("%d",&x);
 91         add(rt,0,V,x);
 92     }
 93     for(int i=1;i<=m;i++){
 94         scanf("%d%d%d",&p,&x,&y);
 95         int k=split(rt,0,V,x,y);
 96         if (p==4)printf("%d\n",sz[k]);
 97         else{
 98             scanf("%d",&z);
 99             if (p==1){
100                 upd_xor(k,0,V,V);
101                 upd_or(k,0,V,(z^V));
102                 upd_xor(k,0,V,V);
103             }
104             if (p==2)upd_or(k,0,V,z);
105             if (p==3)upd_xor(k,0,V,z);
106         }
107         merge(rt,k,0,V);
108     }
109 } 
View Code

 

posted @ 2021-06-22 10:33  PYWBKTDA  阅读(210)  评论(0编辑  收藏  举报