LGP5670 秘籍之反复异或 学习笔记

LGP5670 秘籍之反复异或 学习笔记

Luogu Link

题意简述

给出一个长为 \(n\) 的序列 \(A\)。对于 \(A\) 中的所有元素我们只关心它二进制的后 \(m\) 位。需要支持两种操作:

  • 1 l r x:区间加 \(x\)
  • 2 l r:查询区间 \([l,r]\) 中所有元素异或和。

\(n,q\le 10^5\)\(m\le 10\)

做法解析

这怎么做区间加?别怕,我们的 bitset 可以帮你用“暴力”过掉此题。我们对整个序列开一棵线段树,每个结点上一个 bitset 来维护当前下标区间中每种数出现的次数(刚好,反正偶数次出现一种数在最后求异或和的时候就两两消除掉了,所以我们只关心出现次数的奇偶性,正适合用 bitset)。因为 \(m\le 10\),所以 bitset 大小最大为 \(1024\),还算能接受。区间加就变成了将 bitset 上所有 b[i] 移动到 b[(i+x)%(1<<M)] 了。因为 bitset 也是可以左右移的(至于方向,注意左移是把 b[0]b[1] 方向移动),所以可以直接做。查询,我们得到一个 bitset 作为结果,然后对于所有下标,若 b[i]==1 就将答案异或一个 i

但是这样跑不过去,因为常数太大。对此我们底层分块一下即可。

代码实现

注意 t[u]=((t[u]<<x)|(t[u]>>((1<<M)-x)))&=alb;。这是必要的:这里左移之后的 t[u] 还有超出的一些位,所以要 &=alb

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxMa=1<<10,MaxN=1e5+5;
int N,M,Q,alf,Opt,X,Y,Z,A[MaxN],ans,B=1<<6;
bitset<MaxMa> alb;
struct SegTree{
    int cl[MaxN<<2],cr[MaxN<<2];
    int clen[MaxN<<2],cmid[MaxN<<2];
    bitset<MaxMa> t[MaxN<<2];int tag[MaxN<<2];
    int ls(int u){return u<<1;}
    int rs(int u){return (u<<1)|1;}
    void pushup(int u){t[u]=t[ls(u)]^t[rs(u)];}
    void build(int u,int l,int r){
        cl[u]=l,cr[u]=r,clen[u]=r-l+1;
        if(clen[u]<=B){for(int i=l;i<=r;t[u][A[i]].flip(),i++);return;}
        int mid=(l+r)>>1;cmid[u]=mid;build(ls(u),l,mid),build(rs(u),mid+1,r);pushup(u);
    }
    void maketag(int u,int x){
        tag[u]+=x,tag[u]&=alf;
        t[u]=((t[u]<<x)|(t[u]>>((1<<M)-x)))&=alb;
    }
    void pushdown(int u){
        if(!tag[u])return;int &tt=tag[u];
        maketag(ls(u),tt),maketag(rs(u),tt);tt=0;
    }
    void modify(int u,int dl,int dr,int x){
        if(clen[u]<=B){
            int bl=max(dl,cl[u]),br=min(dr,cr[u]);
            for(int i=bl;i<=br;i++)t[u].flip((A[i]+tag[u])&alf),(A[i]+=x)&=alf,t[u].flip((A[i]+tag[u])&alf);
            return;
        }
        if(dl<=cl[u]&&cr[u]<=dr){maketag(u,x);return;}
        pushdown(u);
        if(dl<=cmid[u])modify(ls(u),dl,dr,x);
        if(dr>cmid[u])modify(rs(u),dl,dr,x);
        pushup(u);
    }
    auto query(int u,int dl,int dr){
        auto res=t[0];
        if(clen[u]<=B){
            int bl=max(dl,cl[u]),br=min(dr,cr[u]);
            for(int i=bl;i<=br;i++)res.flip((A[i]+tag[u])&alf);
            return res;
        }
		if(dl<=cl[u]&&cr[u]<=dr)return t[u];
        pushdown(u);
        if(dl<=cmid[u])res^=query(ls(u),dl,dr);
        if(dr>cmid[u])res^=query(rs(u),dl,dr);
        return res;
    }
}SgT;
int main(){
    readis(N,M,Q);alf=(1<<M)-1;
    for(int i=1;i<=N;i++)readi(A[i]),A[i]&=alf;
    for(int i=0;i<=alf;i++)alb[i]=1;
    SgT.build(1,1,N);
    for(int i=1;i<=Q;i++){
        readis(Opt,X,Y);
        if(Opt==1)readi(Z),SgT.modify(1,X,Y,Z);
        if(Opt==2){
            auto bic=SgT.query(1,X,Y);ans=0;
            for(int i=0;i<=alf;i++)if(bic[i])ans^=i;
            writil(ans);
        }
    }
    
    return 0;
}
posted @ 2025-08-24 15:17  矞龙OrinLoong  阅读(6)  评论(0)    收藏  举报