[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 } 
View Code

 

posted @ 2022-03-02 15:36  PYWBKTDA  阅读(54)  评论(0编辑  收藏  举报