CodeForces

题意:给你一个数组,有两种操作,一种区间xor一个值,一个是查询区间xor的结果的种类数 

做法一:
对于一个给定的区间,我们可以通过求解线性基的方式求出结果的种类数,而现在只不过将其放在线树上维护区间线性基。

用线段树去维护区间合并

#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 1e5;
struct node {
    int bas[30],lazy,st;
    void init() {
        memset(bas,0,sizeof(bas));
        lazy = 0;st = 0;
    }
    int Count() {
        int ans = 0;
        for(int i = 0;i<=29;i++) {
            if(bas[i]) ans++;
        }
        return ans;
    }
    void add(int x) {
        for(int i = 29;i>=0;i--) {
            if((x>>i)&1){
                if(bas[i])x^=bas[i];
                else {
                    bas[i] = x;
                    break;
                }
            }
        }
    }
    node operator + (const node &a) const{
        node ans;  ans.init();
        for(int i = 0;i<=29;i++) {
            ans.add(bas[i]);
            ans.add(a.bas[i]);
        }
        ans.add(st^a.st);
        ans.st = a.st;
        return ans;
    }
}tr[8*maxn],ans;
int n,q;
void pushdown(int st) {
    if(tr[st].lazy) {
        tr[st<<1].lazy ^= tr[st].lazy;
        tr[st<<1].st ^= tr[st].lazy;
        tr[st<<1|1].lazy ^= tr[st].lazy;
        tr[st<<1|1].st ^= tr[st].lazy;
        tr[st].lazy = 0;
    }
}
void build(int l,int r,int st) {
    tr[st].init();
    if(l == r) {
        scanf("%d",&tr[st].st);
        return ;
    }
    int mid = (l+r)>>1;
    build(l,mid,st<<1);
    build(mid+1,r,st<<1|1);
    tr[st] = tr[st<<1] + tr[st<<1|1];
}
void update(int l,int r,int st,int L,int R,int d) {
    if(l>=L && r<=R) {
        tr[st].lazy ^= d;
        tr[st].st ^= d;
        return ;
    }
    pushdown(st);
    int mid = (l+r) >>1;
    if(L<=mid) update(l,mid,st<<1,L,R,d);
    if(R> mid) update(mid+1,r,st<<1|1,L,R,d);
    tr[st] = tr[st<<1] + tr[st<<1|1];
}
void Query(int l,int r,int st,int L,int R) {
    if(l >= L && r <= R) {
        ans = ans + tr[st];
        return ;
    }
    pushdown(st);
    int mid = (l+r) >>1;
    if(L<=mid) Query(l,mid,st<<1,L,R);
    if(R>mid)  Query(mid+1,r,st<<1|1,L,R);
    tr[st] = tr[st<<1] + tr[st<<1|1];
}
int main() {
    int op,l,r,d;
    scanf("%d %d",&n,&q);
    build(1,n,1);
    while(q--) {
        scanf("%d %d %d",&op,&l,&r);
        if(op == 1) {
            scanf("%d",&d);
            update(1,n,1,l,r,d);
        }
        else {
            ans.init();
            Query(1,n,1,l,r);
            printf("%d
",1<<ans.Count());
        }
    }
    return 0;
}
View Code

做法二:

对原序列a进行差分,使得b[i] = a[i] ^ a[i+1],那么al,al+1,al+2,ar可以构成的一个异或和,在al,bl,bl+1,bl+2,br-1中肯定也可以被构造出来,因此二者是等价的。

对于a序列的区间[l,r]的更新实际上b序列上只有bl-1和br被影响,中间的数由于是两两所以抵消掉了。

所以现在就变成了单点更新线段树维护区间线性基,然后再用一个树状数组维护l位置被修改的值,这也用到了差分,这里的作用是要求a[l]的值。

#include <bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int mx = 2e5 + 10;
int n,m,a[mx],b[mx];
int pre[mx],mv;
struct node{
    int gao[31];
    void add(int x){
        for(int i=29;i>=0;i--){
            if(x&(1<<i)){
                if(!gao[i]){
                    gao[i] = x;
                    break;
                }else x ^= gao[i];
            }
        }
    }
    node operator + (node A)const
    {
        node ret = A;
        for(int i=29;i>=0;i--)
        if(gao[i]) ret.add(gao[i]);
        return ret;
    }
}s[mx<<2];
void add(int x,int v){
    while(x<=n){
        pre[x] ^= v;
        x += x&(-x);
    }
}
int getpre(int x){
    int ans = 0;
    while(x){
        ans ^= pre[x];
        x -= x&(-x);
    }
    return ans;
}
void build(int l,int r,int rt)
{
    if(l==r){
        b[l] = a[l]^a[l+1];
        for(int i=29;i>=0;i--)
        if((1<<i)&b[l]){
            s[rt].gao[i] = b[l];
            break;
        }
        return ;
    } 
    int mid = (l+r)>>1;
    build(lson);build(rson);
    s[rt] = s[rt<<1] + s[rt<<1|1];
}
void update(int l,int r,int rt,int M)
{
    if(l==r){
        b[l] ^= mv;
        memset(s[rt].gao,0,sizeof(s[rt].gao));
        for(int i=29;i>=0;i--)
        if((1<<i)&b[l]){
            s[rt].gao[i] = b[l];
            break;
        }
        return ;
    }
    int mid = (l+r)>>1;
    if(M<=mid) update(lson,M);
    else update(rson,M);
    s[rt] = s[rt<<1] + s[rt<<1|1];
} 
node query(int l,int r,int rt,int L,int R)
{
    if(L<=l&&r<=R) return s[rt];
    int mid = (l+r)>>1;
    if(L<=mid&&R>mid) return query(lson,L,R) + query(rson,L,R);
    if(L<=mid) return query(lson,L,R);
    return query(rson,L,R);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    if(n>1) build(1,n-1,1);
    int o,l,r;
    while(m--){
        scanf("%d%d%d",&o,&l,&r);
        if(o==1){
            scanf("%d",&mv);
            add(l,mv);add(r+1,mv);
            if(l>1) update(1,n-1,1,l-1);
            if(r<n) update(1,n-1,1,r);
        }else{
            int v = a[l]^getpre(l);
            if(n==1||l==r) printf("%d
",v?2:1);
            else{
                node ans = query(1,n-1,1,l,r-1);
                ans.add(v);
                int ret = 0;
                for(int i=29;i>=0;i--)
                if(ans.gao[i]) ret++;
                printf("%d
",1<<ret);
            }
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/shuaihui520/p/11350154.html