数据结构好题3.1

原题链接1

原题链接2

本题使用动态开点线段树目的只是防止空间裂开

本题要求维护一个支持①区间求和②区间异或 的数据结构

这个题的数据规模有个很奇怪的地方,ai范围不大

一眼线段树,但区间异或显然不具备区间可加性。一般面对这种情况我们会转为区间求和的问题解决,而异或唯一的转化方法就是转化为二进制。联系数据规模我们会发现最多20位二进制,所以我们可以用线段树分别维护总共20位的状态,显然对区间异或可以转为对区间某一位取反的问题。具体不细说了,想到这里基本就透彻了,细节挺多的

#include<bits/stdc++.h>
using namespace std;
#define re register
#define fo1(l,r) for(re int i=l;i<=r;++i)
#define fo2(l,r) for(re int j=l;j<=r;++j)
#define fo3(l,r) for(re int k=l;k<=r;++k)
#define fo4(l,r) for(re int tt=l;tt<=r;++tt)
#define fo(l) for(re int i=h[l],go;i;i=x[i].last)
#define inf 0x3f3f3f3f
#define INF 0x7fffffffffffffff
#define LL long long
#define itn int
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<3)+(x<<1)+ch-48;
        ch=getchar();
    }
    return x*f;
}
const int N=1e5+10;
int a[N];
struct segmenttree
{
    LL sum[20];
    bool rev[20];
    #define sum(x,y) tree[x].sum[y] 
    #define rev(x,y) tree[x].rev[y] 
}tree[N<<1];
int cnt=1,ls[N<<1],rs[N<<1];
inline int yls(int p){return ls[p]?ls[p]:ls[p]=++cnt;};
inline int yrs(int p){return rs[p]?rs[p]:rs[p]=++cnt;};
#define l(x) yls(x)
#define r(x) yrs(x)
inline void ysp(int p,itn bh,int l,itn r)
{
    if(rev(p,bh))
    {
        int mid=(l+r)>>1;
        sum(l(p),bh)=mid-l+1-sum(l(p),bh);
        sum(r(p),bh)=r-mid-sum(r(p),bh);
        rev(l(p),bh)^=1;
        rev(r(p),bh)^=1;
        rev(p,bh)=0;
    }
    return;
}
inline void build(int p,int bh,int l,int r)
{
    rev(p,bh)=0;
    if(l==r)
    {
        if((a[l]>>bh)&1)
            sum(p,bh)=1;
        else
            sum(p,bh)=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l(p),bh,l,mid);
    build(r(p),bh,mid+1,r);
    sum(p,bh)=sum(l(p),bh)+sum(r(p),bh);
    return;
}
inline LL yask(itn p,int bh,int l,int r,int ll,int rr)
{
    if(ll<=l && r<=rr)
    {
        return sum(p,bh);
    }
    ysp(p,bh,l,r);
    int mid=(l+r)>>1;LL S=0;
    if(ll<=mid)
    {
        S+=yask(l(p),bh,l,mid,ll,rr);
    }
    if(rr>mid)
    {
        S+=yask(r(p),bh,mid+1,r,ll,rr);
    }
    return S;
}
inline void yadd(int p,itn bh,int l,int r,int ll,int rr)
{
    if(ll<=l && r<=rr)
    {
        sum(p,bh)=r-l+1-sum(p,bh);
        rev(p,bh)^=1;
        return;
    }
    ysp(p,bh,l,r);
    itn mid=(l+r)>>1;
    if(ll<=mid)
    {
        yadd(l(p),bh,l,mid,ll,rr);
    }
    if(rr>mid)
    {
        yadd(r(p),bh,mid+1,r,ll,rr);
    }
    sum(p,bh)=sum(l(p),bh)+sum(r(p),bh);
    return;
}
int main()
{
    int n=read();
    fo1(1,n)
    {
        a[i]=read();
    } 
    fo1(0,19)
        build(1,i,1,n);
    int m=read();
    fo1(1,m)
    {
        int ty=read();
        if(ty==1)
        {
            int l=read(),r=read();
            LL ans,ANS=0;
            fo2(0,19)
            {
                ans=yask(1,j,1,n,l,r);
                ans*=(1ll<<j);
                ANS+=ans;
            }
            printf("%lld\n",ANS);
        }
        else
        {
            int l=read(),r=read(),x=read();
            fo2(0,19)
            {
                if((x>>j)&1)
                    yadd(1,j,1,n,l,r);
            }
        }
    }
    return 0;
}

 

posted @ 2023-06-15 21:29  小鱼儿吼吼  阅读(15)  评论(0)    收藏  举报