[uoj671]诡异操作
为了方便,以下记$w=\log \max a_{i}$(本题中$w\le 128$)
建立线段树,对每一个点维护$w$个数,第$i$个数表示区间内(二进制下)第$i$位为1的数个数
将这$w$个数用写成二进制的形式,得到一个$w\times \log len$的01矩阵,转置后即变为$\log len$个数
不妨维护这$\log len$个数,此时2操作即将这些数均$\&$上修改的数,显然可以使用懒标记
在此基础上,up、down和求和均可做到$o(\log len)$的复杂度,进而2和3操作复杂度为$o(q\log^{2}n)$
关于1操作(忽略$v=1$),定位区间的复杂度同样为$o(q\log^{2}n)$,并在区间不全为0时暴力递归
考虑复杂度,每一个区间至多因此递归$w$次(之后一定全为0),总复杂度即$o(w\sum \log len)$
后者可以使用递归式$T(n)=2T(\frac{n}{2})+\log n$计算,根据主定理得$T(n)=o(n)$
最终,总复杂度为$o(q\log^{2}n+nw)$,常数优秀可以通过(用指针存储这$\log len$个数)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300005 4 #define M 20 5 #define ll __uint128_t 6 #define L (k<<1) 7 #define R (L+1) 8 int n,q,p,l,r,len[N<<2]; 9 ll x,a[N],tag[N<<2],Or[N<<2],*f[N<<2],F[N<<3],*it=F; 10 ll read(){ 11 static char s[100]; 12 scanf("%s",s); 13 ll x=0; 14 for(int i=0;s[i];i++){ 15 if ((s[i]>='0')&&(s[i]<='9'))x=((x<<4)|(s[i]-'0')); 16 else x=((x<<4)|(s[i]-'a'+10)); 17 } 18 return x; 19 } 20 void write(ll x){ 21 if (x>=16)write(x>>4); 22 if ((x&15)<10)putchar((x&15)+'0'); 23 else putchar((x&15)-10+'a'); 24 } 25 int Log(int k){ 26 int n=0; 27 while ((1<<n)<=k)n++; 28 return n; 29 } 30 void upd(int k,ll x){ 31 if ((Or[k]&x)==Or[k])return; 32 tag[k]&=x,Or[k]&=x; 33 for(int i=0;i<len[k];i++)f[k][i]&=x; 34 } 35 void up(int k){ 36 x=0,Or[k]=(Or[L]|Or[R]); 37 for(int i=0;i<len[k];i++){ 38 f[k][i]=(f[L][i]^f[R][i]^x); 39 x=((f[L][i]&f[R][i])|(x&(f[L][i]|f[R][i]))); 40 } 41 } 42 void down(int k){ 43 if (~tag[k])upd(L,tag[k]),upd(R,tag[k]),tag[k]=-1; 44 } 45 void build(int k,int l,int r){ 46 len[k]=Log(r-l+1),tag[k]=-1; 47 f[k]=it,it+=len[k]+1; 48 if (l==r){ 49 Or[k]=f[k][0]=a[l]; 50 return; 51 } 52 int mid=(l+r>>1); 53 build(L,l,mid),build(R,mid+1,r); 54 up(k); 55 } 56 void update_div(int k,int l,int r,int x,int y,ll z){ 57 if (!Or[k])return; 58 if (l==r){ 59 Or[k]=f[k][0]=f[k][0]/z; 60 return; 61 } 62 down(k); 63 int mid=(l+r>>1); 64 if (x<=mid)update_div(L,l,mid,x,y,z); 65 if (mid<y)update_div(R,mid+1,r,x,y,z); 66 up(k); 67 } 68 void update_and(int k,int l,int r,int x,int y,ll z){ 69 if ((Or[k]&z)==Or[k])return; 70 if ((x<=l)&&(r<=y)){ 71 upd(k,z); 72 return; 73 } 74 down(k); 75 int mid=(l+r>>1); 76 if (x<=mid)update_and(L,l,mid,x,y,z); 77 if (mid<y)update_and(R,mid+1,r,x,y,z); 78 up(k); 79 } 80 ll query(int k,int l,int r,int x,int y){ 81 if (!Or[k])return 0; 82 ll sum=0; 83 if ((x<=l)&&(r<=y)){ 84 for(int i=0;i<len[k];i++)sum+=(f[k][i]<<i); 85 return sum; 86 } 87 down(k); 88 int mid=(l+r>>1); 89 if (x<=mid)sum+=query(L,l,mid,x,y); 90 if (mid<y)sum+=query(R,mid+1,r,x,y); 91 return sum; 92 } 93 int main(){ 94 scanf("%d%d",&n,&q); 95 for(int i=1;i<=n;i++)a[i]=read(); 96 build(1,1,n); 97 for(int i=1;i<=q;i++){ 98 scanf("%d%d%d",&p,&l,&r); 99 if (p==1){ 100 x=read(); 101 if (x>1)update_div(1,1,n,l,r,x); 102 } 103 if (p==2){ 104 x=read(); 105 update_and(1,1,n,l,r,x); 106 } 107 if (p==3)write(query(1,1,n,l,r)),putchar('\n'); 108 } 109 return 0; 110 }