Luogu5607 [Ynoi2013] 无力回天 NOI2017

原题链接:https://www.luogu.com.cn/problem/P5607

无力回天

题目描述

给你一个长度为 n 的整数序列 a 1 a_1 a1 , a 2 a_2 a2 , … \ldots , a n a_n an ,你需要实现以下两种操作,每个操作都可以用四个整数 o p t    l    r    v opt\;l\;r\;v optlrv 来表示:

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

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

输入格式

第一行有两个正整数 n , m n,m n,m。 第二行有 n n n 个整数表示给你的序列。 之后 m m m 行每行有四个整数 o p t , l , r , v opt, l, r, v opt,l,r,v表示一个操作。

输出格式

对于每个 o p t = 2 opt=2 opt=2 的操作,输出一行一个数表示答案~

输入输出样例

输入 #1
4 5
1 14 51 4
2 1 3 0
1 2 3 3
2 1 4 10
1 1 4 514
2 3 4 2
输出 #1
61
63
560

说明/提示

Idea:nzhtl1477,Solution:nzhtl1477,Code:nzhtl1477,Data:nzhtl1477

对于 100 % 100\% 100% 的数据,满足 1 ≤ n , m ≤ 5 × 1 0 4 1 \le n , m \le 5 \times 10^4 1n,m5×104 ,值域在 [ 0 , 1 0 9 ] [0,10^9] [0,109] 之间

题解

好家伙,做省选数据结构本来是想复习数据结构,结果都是加一些非数据结构骚操作。

通过回忆,要求最大异或和,需要一个叫做线性基的东西,而线性基的大小是 O ( l o g 2 值 域 大 小 ) O(log_2值域大小) O(log2)的,对于这道题就是 30 30 30,那么自然想到可以通过线段树来维护区间的线性基,复杂度为 O ( n l o g 2 n l o g 2 2 值 域 大 小 ) O(nlog_2nlog_2^2值域大小) O(nlog2nlog22)三个log满足时限。

但是问题来了,本题还有区间异或的操作,因为 v , a 1 , a 2 ⋯   , a n v,a_1,a_2\cdots ,a_n v,a1,a2,an的线性基不一定等于 a 1 ⊕ v , a 2 ⊕ v , ⋯   , a n ⊕ v a_1\oplus v, a_2 \oplus v,\cdots,a_n\oplus v a1v,a2v,,anv的线性基,所以打标记区间修改的思路不成了。我们注意到,区间修改不容易解决,但是单点修改的话就只需要合并线性基就行了。区间转单点,就会想到差分的思路。再深入考察,发现异或运算是与自己可逆的(即 a ⊕ b ⊕ b = a ) a \oplus b \oplus b =a) abb=a),同时满足交换律结合律,所以差分就有了实现的可能。

b i = a i − 1 ⊕ a i b_i=a_{i-1}\oplus a_i bi=ai1ai,则满足如下性质:
a i = b 1 ⊕ b 2 ⊕ ⋯ ⊕ b i a_i=b_1\oplus b_2\oplus\cdots\oplus b_i ai=b1b2bi

b l + 1 ∼ b r b_{l+1}\sim b_r bl+1br是由 a l ∼ a r a_l\sim a_r alar两两异或得到的,所以 a l , b l + 1 ∼ b r a_l,b_{l+1}\sim b_r al,bl+1br的线性基与 a l ∼ a r a_l\sim a_r alar的线性基相同。于是就有了最终的解决方案:用线段树维护 { b i } \{b_i\} { bi}的线性基,然后线段树/树状数组维护 { b i } \{b_i\} { bi}。询问区间 [ l , r ] [l,r] [l,r]时,查询 b l + 1 ∼ r b_{l+1\sim r} bl+1r的线性基,再求 b 1 ∼ l b_{1\sim l} b1l的异或和得到 a l a_l al加入线性基,之后按位贪心就能得答案;修改就是基本的差分数列修改。

代码

#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
#define lb(v) v&(-v)
using namespace std;
const int M=5e4+5;
struct node{
    
    int base[35];}tree[M<<2];
int n,m,que[M],xsum[M];
void xadd(int v,int x){
    
    for(;v<=n;v+=lb(v))xsum[v]^=x;}
int xask(int v){
    
    int r=0;for(;v;v-=lb(v))r^=xsum[v];return r;}
node up(node a,node b)
{
    
    
    for(int i=0;i<=30;++i)
    for(int j=30;j>=0;--j)
    if(a.base[i]&(1<<j))
    if(b.base[j])a.base[i]^=b.base[j];
    else {
    
    b.base[j]=a.base[i];break;}
    return b;
}
void build(int v,int le,int ri)
{
    
    
    if(le==ri){
    
    for(int i=30;i>=0;--i)if(que[le]&(1<<i)){
    
    tree[v].base[i]=que[le];break;}return;}
    int mid=le+ri>>1;
    build(ls,le,mid);build(rs,mid+1,ri);
    tree[v]=up(tree[ls],tree[rs]);
}
void modify(int v,int le,int ri,int x,int val)
{
    
    
    if(le==ri)
    {
    
    
        memset(tree[v].base,0,sizeof(tree[v].base));
        for(int i=30;i>=0;--i)if(val&(1<<i)){
    
    tree[v].base[i]=val;break;}
        return;
    }
    int mid=le+ri>>1;
    if(x<=mid)modify(ls,le,mid,x,val);
    else modify(rs,mid+1,ri,x,val);
    tree[v]=up(tree[ls],tree[rs]);
}
node ask(int v,int le,int ri,int ll,int rr)
{
    
    
    if(ll<=le&&ri<=rr)return tree[v];
    int mid=le+ri>>1;
    node r;memset(r.base,0,sizeof(r.base));
    if(ll<=mid)r=ask(ls,le,mid,ll,rr);
    if(mid<rr)r=up(r,ask(rs,mid+1,ri,ll,rr));
    return r;
}
void in()
{
    
    
    scanf("%d%d",&n,&m);
    for(int i=1,a=0,b;i<=n;++i)scanf("%d",&b),xadd(i,que[i]=a^b),a=b;
}
void ac()
{
    
    
    build(1,1,n);
    node b;
    for(int op,l,r,v,a;m--;)
    {
    
    
        scanf("%d%d%d%d",&op,&l,&r,&v);
        if(op-1)
        {
    
    
            b=ask(1,1,n,l+1,r);
            a=xask(l);
            for(int i=30;i>=0;--i)
            if(a&(1<<i))
            if(b.base[i])a^=b.base[i];
            else {
    
    b.base[i]=a;break;}
            for(int i=30;i>=0;--i)v=max(v,v^b.base[i]);
            printf("%d\n",v);
        }
        else xadd(l,v),xadd(r+1,v),modify(1,1,n,l,que[l]^=v),modify(1,1,n,r+1,que[r+1]^=v);
    }
}
int main()
{
    
    
    in(),ac();
    system("pause");
}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/113920907