思路

题目要求区间 的的所有子集的与的和。让我们来想想与有什么特殊的性质。
数据给出 不超过 ,同时作为位运算的与,我们可以看看每个数的二进制的每一位有什么用。
我们知道,不同数互与操作时,二进制下每一位是互不干扰的,这就给我们一个思路了。我们可以把所有区间拆成 个区间,分别代表二进制下不同位的区间。那这和问题要问的有什么关系呢?
其实很容易发现,拆开区间后,我们一个区间子集的所有与操作和加起来其实就是这32个区间的与的和加起来。现在这 个区间分别代表的就是每一位的区间,这样计算大大简化。那么题目要求的就是
解释一下这式子什么意思,首先累加 个位的区间的答案(刚才说过的),接着考虑对于第 位时,如果区间有 个数是满足这意味是 的话,那么这一位子集的答案不为 的就是这 个数的随机组合,随机组合其实有 ,注意取0个时不是答案,其实也就是 ,而 ,所以只要求出该位下区间有多少个数满足情况就可以算了。
可以用线段树维护 ,但是我线段树写炸了,用了常数更小的树状数组维护QAQ。建议预处理出 的次方数,然后 调用。

#include<iostream>
#include<algorithm>

using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int mod=1e9+7;

ll a[maxn],n,m,mx,maxv,op,c,d;
ll lg[maxn],t[32][maxn];
//struct node{
//    int l,r,w;
//}t[32][maxn<<2];

char buf[1<<20],*P1=buf,*P2=buf;    
//#define gc() getchar()
#define gc() (P1==P2&&(P2=(P1=buf)+fread(buf,1,1<<20,stdin),P1==P2)?EOF:*P1++)
#define TT template<class T>inline
TT void read(T&x)
{
       x=0; char c=gc(); bool f=0;
       while(c<48||c>57){f^=c=='-',c=gc();}
       while(47<c&&c<58)x=(x<<3)+(x<<1)+(c^48),c=gc();
       if(f)x=-x;
}

//ll qpow(ll a,ll b)
//{
//    ll ans=1;
//    while(b)
//    {
//        if(b&1)ans=ans*a%mod;
//        b>>=1; a=a*a%mod;
//    }
//    return ans;
//}
//
//inline void pushup(int k,int p)
//{
//    t[p][k].w=t[p][k<<1].w+t[p][k<<1|1].w;
//}
//
//inline void build(int k,int l,int r)
//{
//    for(int i=0;i<=mx;i++)t[i][k].l=l,t[i][k].r=r;
//    if(l==r)
//    {
//        for(int i=0;i<=mx;i++)t[i][k].w=(a[l]&(1<<i))>0;
//        return;
//    }
//    int mid=l+r>>1;
//    build(k<<1,l,mid);
//    build(k<<1|1,mid+1,r);
//    for(int i=0;i<=mx;i++)pushup(k,i);
//    return;
//}
//
//inline void update(int k,int p,int u,int v)
//{
//    int l=t[p][k].l,r=t[p][k].r;
//    if(l==r)
//    {
//        t[p][k].w=v; return;
//    }
//    int mid=l+r>>1;
//    if(u<=mid)update(k<<1,p,u,v);
//    else update(k<<1|1,p,u,v);
//    pushup(k,p);
//    return;
//}
//
//inline int query(int k,int p,int l,int r)
//{
//    int x=t[p][k].l,y=t[p][k].r;
//    if(l<=x&&y<=r)return t[p][k].w;
//    int mid=x+y>>1;
//    int res=0;
//    if(l<=mid)res+=query(k<<1,p,l,r);
//    if(mid<r)res+=query(k<<1|1,p,l,r);
//    return res;
//}

inline int lowbit(int x)
{
    return x&(-x);
}

inline void update(int x,int p,int y)
{
    for(int i=x;i<=n;i+=lowbit(i))t[p][i]+=y;
}

inline int query(int x,int p)
{
    int res=0;
    for(int i=x;i>=1;i-=lowbit(i))res+=t[p][i];
    return res;
}

int main()
{
    read(n); mx=31; lg[0]=1;
    for(int i=1;i<=n;i++)
    {
        read(a[i]); int k=a[i],cnt=0;
        while(k)
        {
            if(k&1)update(i,cnt,1);
            k>>=1; cnt++;
        }
    }
    for(int i=1;i<=n;i++)lg[i]=lg[i-1]*2%mod;
//    build(1,1,n);
    read(m);
    while(m--)
    {
        read(op),read(c),read(d);
        ll ans=0;
        if(op==1)
        {
            for(int i=0;i<=mx;i++)
            {
                if((a[c]&(1<<i))!=(d&(1<<i)))
                {
//                    update(1,i,c,(d&(1<<i))>0);
                    update(c,i,(d&(1<<i))>0?1:-1);
                }
            }
            a[c]=d;
        }
        else
        {
            ll ans=0;
            for(int i=0;i<=mx;i++)
            {
//                ans+=lg[i]*(lg[query(1,i,c,d)]-1)%mod;
                ans=(ans+lg[i]*(lg[query(d,i)-query(c-1,i)]-1))%mod;
            }
            printf("%lld\n",ans);
        } 
    } 
    return 0;
}