codeforces gym 100739 AQueries(区间的子区间异或和+单点修改)

题:https://codeforces.com/gym/100739/problem/A

题意:俩个操作,见标题。

分析:1、区间异或我们肯定要将序列的每个数进行二进制拆位+线段树,由题目要求只需拆出10位;

   2、对于查询操作,我们可通过区间[L,R]中每个二进制位上区间异或和为1的子区间有多少个来算出答案,因为是要求子区间异或和之和,所以在每个二进制位上就表示为区间[L,R]的所有子区间的异或的值的对应二进制位上为1  的子区间的个数,所以线段树要维护的就是这个东西,由此需要其它东西来“协力”维护;

   3、对于每一棵线段树的每一个节点,我们维护:𝑑表示这段区间的异或和; 𝑙0,𝑙1表示子区间从左端点开始,异或和为0/1的子区间有多少个; 𝑟0,𝑟1表示子区间从右端点开始,异或和为0/1的子区间有多少个; 𝑠0,𝑠1表示异或和为0/1的子区间一共有多少个。(这个方法和线段树维护最大子段和的方法类似)

   4、合并操作:假设𝑥的左儿子𝑙𝑠,右儿子𝑟𝑠,那么:

𝑠𝑥,0 = 𝑠𝑙𝑠,0 + 𝑠𝑟𝑠,0 + 𝑟𝑙𝑠,0𝑙𝑟𝑠,0 + 𝑟𝑙𝑠,1𝑙𝑟𝑠,1

𝑠𝑥,1 = 𝑠𝑙𝑠,1 + 𝑠𝑟𝑠,1 + 𝑟𝑙𝑠,1𝑙𝑟𝑠,0 + 𝑟𝑙𝑠,0𝑙𝑟𝑠,1

𝑙𝑥,0 = 𝑙𝑙𝑠,0 + 𝑙𝑟𝑠,𝑑𝑙𝑠

𝑙𝑥,1 = 𝑙𝑙𝑠,1 + 𝑙𝑟𝑠,𝑑𝑙𝑠 xor 1 

/**

**/
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
const int mod=4001;
typedef long long ll;
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
struct node{
    int d,L[2],R[2],S[2];
}tr[M<<2][11];
int a[M][11],tmp[M];
void up(int root){
    int lc=root<<1,rc=root<<1|1;
    for(int j=0;j<10;j++){
        int dl=tr[lc][j].d;
        int dr=tr[rc][j].d;
        tr[root][j].d=dl^dr;
        tr[root][j].L[0]=(tr[lc][j].L[0]+tr[rc][j].L[dl==0?0:1])%mod;
        tr[root][j].L[1]=(tr[lc][j].L[1]+tr[rc][j].L[dl==0?1:0])%mod;
        tr[root][j].R[0]=(tr[rc][j].R[0]+tr[lc][j].R[dr==0?0:1])%mod;
        tr[root][j].R[1]=(tr[rc][j].R[1]+tr[lc][j].R[dr==0?1:0])%mod;
        tr[root][j].S[0]=(tr[lc][j].S[0]+tr[rc][j].S[0]+(tr[lc][j].R[0]*tr[rc][j].L[0])%mod+(tr[lc][j].R[1]*tr[rc][j].L[1])%mod)%mod;
        tr[root][j].S[1]=(tr[lc][j].S[1]+tr[rc][j].S[1]+(tr[lc][j].R[0]*tr[rc][j].L[1])%mod+(tr[lc][j].R[1]*tr[rc][j].L[0])%mod)%mod;
    }
}
node Merge(node x,node y){
    node res;
    res.d=res.L[0]=res.L[1]=res.R[0]=res.R[1]=res.S[0]=res.S[1]=0;

    int dl=x.d;
    int dr=y.d;
    res.d=dl^dr;
    res.L[0]=(x.L[0]+y.L[dl==0?0:1])%mod;
    res.L[1]=(x.L[1]+y.L[dl==0?1:0])%mod;
    res.R[0]=(y.R[0]+x.R[dr==0?0:1])%mod;
    res.R[1]=(y.R[1]+x.R[dr==0?1:0])%mod;
    res.S[0]=(x.S[0]+y.S[0]+(x.R[0]*y.L[0])%mod+(x.R[1]*y.L[1])%mod)%mod;
    res.S[1]=(x.S[1]+y.S[1]+(x.R[0]*y.L[1])%mod+(x.R[1]*y.L[0])%mod)%mod;
    return res;
}
void build(int root,int l,int r){
    if(l==r){
        for(int j=0;j<10;j++){
            int x=a[l][j];
            tr[root][j].d=x;
            tr[root][j].L[x]=tr[root][j].R[x]=tr[root][j].S[x]=1;
        }
        return ;
    }
    int midd=(l+r)>>1;
    build(lson);
    build(rson);
    up(root);
}
void update(int pos,int root,int l,int r){
    if(l==r){
        for(int j=0;j<10;j++){
            int now=tmp[j];
            tr[root][j].d=now;
            tr[root][j].L[now]=tr[root][j].R[now]=tr[root][j].S[now]=1;
            tr[root][j].L[now^1]=tr[root][j].R[now^1]=tr[root][j].S[now^1]=0;
        }
        return ;
    }
    int midd=(l+r)>>1;
    if(pos<=midd)
        update(pos,lson);
    else
        update(pos,rson);
    up(root);
}

node query(int L,int R,int sign,int root,int l,int r){
    if(L<=l&&r<=R){
        return tr[root][sign];
    }
    int midd=(l+r)>>1;
    node res;
    res.d=res.L[0]=res.L[1]=res.R[0]=res.R[1]=res.S[0]=res.S[1]=0;
    if(L<=midd)
        res=Merge(res,query(L,R,sign,lson));
    if(R>midd)
        res=Merge(res,query(L,R,sign,rson));
    return res;
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<=4*n;i++)
        for(int j=0;j<10;j++)
            tr[i][j].d=tr[i][j].L[0]=tr[i][j].L[1]=tr[i][j].R[0]=tr[i][j].R[1]=tr[i][j].S[0]=tr[i][j].S[1]=0;
    for(int x,i=1;i<=n;i++){
        scanf("%d",&x);
        for(int j=0;j<10;j++)
            if(x&(1<<j))
                a[i][j]=1;
    }
    build(1,1,n);
    while(m--){
        int op,x,y;
        scanf("%d%d%d",&op,&x,&y);
        if(op==1){
            memset(tmp,0,sizeof(tmp));
            for(int j=0;j<10;j++)
                if(y&(1<<j))
                    tmp[j]=1;
            update(x,1,1,n);
        }
        else{
            ll ans=0;
            for(int j=0;j<10;j++){
                node res=query(x,y,j,1,1,n);
                ans=(ans+(1ll<<j)*res.S[1]%mod)%mod;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}
View Code

 

posted @ 2020-04-02 12:07  starve_to_death  阅读(380)  评论(0编辑  收藏  举报