[Ynoi2013] 无力回天 线段树+线性基

P5607 [Ynoi2013] 无力回天 线段树+线性基

题意

给你一个长度为 n 的整数序列 \(a_1\), \(a_2\), \(\ldots\), \(a_n\) ,你需要实现以下两种操作,每个操作都可以用四个整数 \(opt\;l\;r\;v\) 来表示:

\(opt=1\) 时,代表把一个区间 \([l,r]\) 内的所有数都 xor 上 \(v\)

\(opt=2\) 时, 查询一个区间 \([l,r]\) 内选任意个数(包括 \(0\) 个)数 xor 起来,这个值与 \(v\) 的最大 xor 和是多少。

思路

思路参考

区间修改,可以通过差分解决。

经典性质:\(a_l,a_{l+1},...,a_r\) 的线性基和 \(a_l,b_{l+1},...,b_r\)相同。

然后用线段树维护就可以。合并两个线性基即可。

代码

#include<bits/stdc++.h>

using namespace std;

#define ff first
#define ss second
#define pb push_back
#define all(u) u.begin(), u.end()
#define endl '\n'
#define debug(x) cout<<#x<<":"<<x<<endl;

typedef pair<int, int> PII;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10, M = 105;
const int mod = 1e9 + 7;
const int cases = 0;

struct node{
    int l,r;
    int p[32];
    int sum;
    void insert(int x){
        for(int i=31;i>=0;i--){
            if(x>>i&1){
                if(!p[i]){
                  p[i]=x;
                  return;
                }
                x^=p[i];
            } 
        }
    }

    void insert(node &u){
        for(int i=31;i>=0;i--){
            if(u.p[i]) insert(u.p[i]);
        }
    }

    void Clear(){
        memset(p,0,sizeof p);
        return;
    }
}tr[N*4];

int a[N],b[N];

#define ls u<<1
#define rs u<<1|1

void pushup(node &u,node &l,node &r){
    u.sum=l.sum^r.sum;
    u.Clear();
    u.insert(l);
    u.insert(r);
}

void pushup(int u){
    pushup(tr[u],tr[ls],tr[rs]);
}

void build(int u,int l,int r){
   tr[u].l=l;tr[u].r=r;
   if(l==r){
    tr[u].insert(b[l]);
    tr[u].sum=b[l];
    return;
   }
   int mid=tr[u].l+tr[u].r>>1;
   build(ls,l,mid);
   build(rs,mid+1,r);
   pushup(u);
}

void modify(int u,int x,int v){
    if(tr[u].l==tr[u].r){
        tr[u].Clear();
        tr[u].sum=(b[x]^=v);
        tr[u].insert(b[x]);
        return;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(x<=mid) modify(ls,x,v);
    else modify(rs,x,v);
    pushup(u);
}

node query(int u,int l,int r){//区间查询
    if(l>r) return tr[0];
    if(l<=tr[u].l&&tr[u].r<=r){
        return tr[u];
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(r<=mid) return query(ls,l,r);
    if(l>mid) return query(rs,l,r);
    node ret;
    node L=query(ls,l,r);
    node R=query(rs,l,r);
    pushup(ret,L,R); 
    return ret;
}

void Showball(){
   int n,m;
   cin>>n>>m;
   for(int i=1;i<=n;i++){
    cin>>a[i];
    b[i]=a[i]^a[i-1];
   }
   build(1,1,n);
   while(m--){
    int opt,l,r,v;
    cin>>opt>>l>>r>>v;
    if(opt==1){
        modify(1,l,v);
        if(r<n) modify(1,r+1,v);
    }else{
        node ret=query(1,l+1,r);
        int al=query(1,1,l).sum;
        ret.insert(al);
        for(int i=31;i>=0;i--) v=max(v,v^ret.p[i]);
        cout<<v<<endl;
    }
   }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T=1;
    if(cases) cin>>T;
    while(T--)
    Showball();
    return 0;
}
posted @ 2024-05-10 23:56  Showball  阅读(6)  评论(0编辑  收藏  举报