题解 P5607 【[Ynoi2013] 无力回天 NOI2017】

P5607 [Ynoi2013] 无力回天 NOI2017

这是一道在 Ynoi 中很水的题。


题意

求作一种数据结构,支持区间异或,区间查询任意个数异或所给数的最大值。

思路

显然,第二个操作可以简单地使用数据结构 线性基 维护。

但是我们还有修改操作...

由于线性基不支持修改、删除,于是区间异或就很难处理。

于是我们思考差分,使区间修改 -> 单点修改。

biaixorai1,于是区间修改操作 aiaixorv(i[l,r]) 就转变为了两次单点修改 blblxorv,br+1br+1xorv

很显然 b 数组可以使用树状数组维护。

然后转为单点修改,可以考虑使用分块/线段树维护,其中每个节点维护的是包含 l,r 区间中的 b 数组构成的线性基。

于是我一开始打出了分块,于是我打出了分块,疯狂卡常,还是 95pts 没卡过 ...

后来放弃了,我就开始打线段树,结果一次过...

为什么会这样呢?分块的复杂度为 O((n+m)nlog2w),而线段树的复杂度为 O((n+m)lognlog2w) 由于一个 log 比一个 n 小很多,所以运行起来会快很多。

所以得出结论,以后合并节点的复杂度高时不要用分块,要用线段树。

下面给出代码:

分块:

#include <bits/stdc++.h>
using namespace std;
namespace IO{
    int len=0;
    char ibuf[18<<20],*ss,out[(1<<22)+1];
    inline int read(){
        register int u=0;
        while(*ss<48) ss++;
        while(*ss>32)
           u=u*10+*ss++-48;
        return u;
    }
    inline void write(int x){
        if(x>9)write(x/10);
        out[len++]=x%10+48;
    }
}
using namespace IO;
struct Linebase{
    int sz,p[30];
    Linebase(){
        p[0]=0;
        p[1]=0;
        p[2]=0;
        p[3]=0;
        p[4]=0;
        p[5]=0;
        p[6]=0;
        p[7]=0;
        p[8]=0;
        p[9]=0;
        p[10]=0;
        p[11]=0;
        p[12]=0;
        p[13]=0;
        p[14]=0;
        p[15]=0;
        p[16]=0;
        p[17]=0;
        p[18]=0;
        p[19]=0;
        p[20]=0;
        p[21]=0;
        p[22]=0;
        p[23]=0;
        p[24]=0;
        p[25]=0;
        p[26]=0;
        p[27]=0;
        p[28]=0;
        p[29]=0;
        sz=0;
    }
    inline friend Linebase operator +(Linebase a,int b){
        if(a.sz==30||!b) return a;
        for(register int i=29;i>=0;i--){
            if(b>>i&1){
                if(a.p[i]){
                    b^=a.p[i];
                }else{
                    a.p[i]=b;
                    a.sz++;
                    return a;
                }
            }
        }
        return a;
    }
    inline friend Linebase operator +(Linebase a,Linebase b){
        if(a.sz==30) return a;
        if(b.sz==30) return b;
        for(register int i=29;i>=0;i--){
            if(b.p[i])a=a+b.p[i];
        }
        return a;
    }
    inline int getmax(int v){
        v=max(v,v^p[29]);
        v=max(v,v^p[28]);
        v=max(v,v^p[27]);
        v=max(v,v^p[26]);
        v=max(v,v^p[25]);
        v=max(v,v^p[24]);
        v=max(v,v^p[23]);
        v=max(v,v^p[22]);
        v=max(v,v^p[21]);
        v=max(v,v^p[20]);
        v=max(v,v^p[19]);
        v=max(v,v^p[18]);
        v=max(v,v^p[17]);
        v=max(v,v^p[16]);
        v=max(v,v^p[15]);
        v=max(v,v^p[14]);
        v=max(v,v^p[13]);
        v=max(v,v^p[12]);
        v=max(v,v^p[11]);
        v=max(v,v^p[10]);
        v=max(v,v^p[9]);
        v=max(v,v^p[8]);
        v=max(v,v^p[7]);
        v=max(v,v^p[6]);
        v=max(v,v^p[5]);
        v=max(v,v^p[4]);
        v=max(v,v^p[3]);
        v=max(v,v^p[2]);
        v=max(v,v^p[1]);
        v=max(v,v^p[0]);
        return v;
    }
};
int t[50010],n,m,a[50010],block,belong[50010],cnt;
inline void upd(int x,int k){
    for(register int i=x;i<=n;i+=(i&-i)){
        t[i]^=k;
    }
}
inline int query(int x){
    register int ans=0;
    for(register int i=x;i>=1;i-=(i&-i)){
        ans^=t[i];
    }
    return ans;
}
struct Block{
    int l,r;
    Linebase s;
    Block(){l=r=0;}
    inline void cg(){
        s=Linebase();
        register int i=l;
        for(;i+7<=r;i+=8){
            s=s+a[i];
            s=s+a[i+1];
            s=s+a[i+2];
            s=s+a[i+3];
            s=s+a[i+4];
            s=s+a[i+5];
            s=s+a[i+6];
            s=s+a[i+7];
        }
        for(;i<=r;i++){
            s=s+a[i];
        }
    }
}b[150];
inline void modify(int p,int k){
    register int bl=belong[p];
    a[p]^=k;
    b[bl].cg();
}
inline Linebase query(int l,int r){
    register int bl=belong[l],br=belong[r];
    Linebase c;
    if(bl==br){
        for(int i=l;i<=r;i++){
            c=c+a[i];
        }
        return c;
    }
    for(int i=l;i<=b[bl].r;i++){
        c=c+a[i];
    }
    for(int i=bl+1;i<=br-1;i++){
        c=c+b[i].s;
    }
    for(int i=b[br].l;i<=r;i++){
        c=c+a[i];
    }
    return c;
}
int main(){
    fread(ss=ibuf,1,18<<20,stdin);
    n=read(),m=read();
    for(register int i=1;i<=n;i++){
        a[i]=read();
    }
    for(register int i=n;i>=2;i--){
        a[i]^=a[i-1];
    }
    for(register int i=1;i<=n;i++){
        upd(i,a[i]);
    }
    block=13*sqrt(n)/8;
    for(register int i=1;i<=n;i+=block){
        cnt++;
        b[cnt].l=i;
        b[cnt].r=min(i+block-1,n);
    }
    for(register int i=1;i<=cnt;i++){
        for(register int j=b[i].l;j<=b[i].r;j++){
            b[i].s=b[i].s+a[j];
            belong[j]=i;
        }
    }
    while(m--){
        register int opt=read(),l=read(),r=read(),v=read();
        if(opt==1){
            if(belong[l]!=belong[r]){
                upd(l,v);
                modify(l,v);
                if(r<n){
                    upd(r+1,v);
                    modify(r+1,v);
                }
            }else{
                a[l]^=v;
                upd(l,v);
                if(r<n){
                    a[r+1]^=v;
                    upd(r+1,v);
                }
                b[belong[l]].cg();
            }
        }else{
            register int k=query(l);
            if(l==r){
                write(max(v,v^k));
                out[len++]='\n';
            }else{
                Linebase c=query(l+1,r)+k;
                write(c.getmax(v));
                out[len++]='\n';
            }
        }
    }
    fwrite(out,1,len,stdout);
    return 0;
}
 /*
  Time:27.32s
  Memory:7.20MB
  TLE 3.07s on Test #9
  95pts
  */

线段树:

#include <bits/stdc++.h>
using namespace std;
namespace IO{
    int len=0;
    char ibuf[18<<20],*ss,out[(1<<22)+1];
    inline int read(){
        register int u=0;
        while(*ss<48) ss++;
        while(*ss>32)
           u=u*10+*ss++-48;
        return u;
    }
    inline void write(int x){
        if(x>9)write(x/10);
        out[len++]=x%10+48;
    }
}
using namespace IO;
struct Linebase{
    int sz,p[30];
    Linebase(){
        p[0]=0;
        p[1]=0;
        p[2]=0;
        p[3]=0;
        p[4]=0;
        p[5]=0;
        p[6]=0;
        p[7]=0;
        p[8]=0;
        p[9]=0;
        p[10]=0;
        p[11]=0;
        p[12]=0;
        p[13]=0;
        p[14]=0;
        p[15]=0;
        p[16]=0;
        p[17]=0;
        p[18]=0;
        p[19]=0;
        p[20]=0;
        p[21]=0;
        p[22]=0;
        p[23]=0;
        p[24]=0;
        p[25]=0;
        p[26]=0;
        p[27]=0;
        p[28]=0;
        p[29]=0;
        sz=0;
    }
    inline void insert(int b){
        if(sz==30||!b) return ;
        for(register int i=29;i>=0;i--){
            if(b>>i&1){
                if(p[i]){
                    b^=p[i];
                }else{
                    p[i]=b;
                    sz++;
                    return ;
                }
            }
        }
        return ;
    }
    inline friend Linebase operator +(Linebase a,Linebase b){
        if(a.sz==30) return a;
        if(b.sz==30) return b;
        for(register int i=29;i>=0;i--){
            if(b.p[i])a.insert(b.p[i]);
        }
        return a;
    }
    inline int getmax(int v){
        v=max(v,v^p[29]);
        v=max(v,v^p[28]);
        v=max(v,v^p[27]);
        v=max(v,v^p[26]);
        v=max(v,v^p[25]);
        v=max(v,v^p[24]);
        v=max(v,v^p[23]);
        v=max(v,v^p[22]);
        v=max(v,v^p[21]);
        v=max(v,v^p[20]);
        v=max(v,v^p[19]);
        v=max(v,v^p[18]);
        v=max(v,v^p[17]);
        v=max(v,v^p[16]);
        v=max(v,v^p[15]);
        v=max(v,v^p[14]);
        v=max(v,v^p[13]);
        v=max(v,v^p[12]);
        v=max(v,v^p[11]);
        v=max(v,v^p[10]);
        v=max(v,v^p[9]);
        v=max(v,v^p[8]);
        v=max(v,v^p[7]);
        v=max(v,v^p[6]);
        v=max(v,v^p[5]);
        v=max(v,v^p[4]);
        v=max(v,v^p[3]);
        v=max(v,v^p[2]);
        v=max(v,v^p[1]);
        v=max(v,v^p[0]);
        return v;
    }
};
int t[50010],n,m,a[50010],block,belong[50010],cnt;
inline void upd(int x,int k){
    for(register int i=x;i<=n;i+=(i&-i)){
        t[i]^=k;
    }
}
inline int query(int x){
    register int ans=0;
    for(register int i=x;i>=1;i-=(i&-i)){
        ans^=t[i];
    }
    return ans;
}
struct Seg_tree{
    Linebase b[200010];
    inline void build(int l,int r,int rt){
        for(int i=l;i<=r;i++){
            b[rt].insert(a[i]);
        }
        if(l==r) return;
        int mid=l+r>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
    }
    inline void modify(int pos,int l,int r,int rt,int k){
        if(l==r){
            b[rt]=Linebase();
            a[l]^=k;
            b[rt].insert(a[l]);
            return ;
        }
        int mid=l+r>>1;
        if(pos<=mid) modify(pos,l,mid,rt<<1,k);
        else     modify(pos,mid+1,r,rt<<1|1,k);
        b[rt]=b[rt<<1]+b[rt<<1|1];
    }
    inline Linebase query(int ql,int qr,int rt,int l,int r){
        if(ql==l&&qr==r) return b[rt];
        int mid=ql+qr>>1;
        if(mid>=r) return query(ql,mid,rt<<1,l,r);
        else if(mid<l) return query(mid+1,qr,rt<<1|1,l,r);
        else return query(ql,mid,rt<<1,l,mid)+query(mid+1,qr,rt<<1|1,mid+1,r);
    }
}T;
int main(){
    fread(ss=ibuf,1,18<<20,stdin);
    n=read(),m=read();
    for(register int i=1;i<=n;i++){
        a[i]=read();
    }
    for(register int i=n;i>=2;i--){
        a[i]^=a[i-1];
    }
    for(register int i=1;i<=n;i++){
        upd(i,a[i]);
    }
    T.build(1,n,1);
    while(m--){
        register int opt=read(),l=read(),r=read(),v=read();
        if(opt==1){
            upd(l,v);
            T.modify(l,1,n,1,v);
            if(r<n){
                upd(r+1,v);
                T.modify(r+1,1,n,1,v);
            }
        }else{
            register int k=query(l);
            if(l==r){
                write(max(v,v^k));
                out[len++]='\n';
            }else{
                Linebase c=T.query(1,n,1,l+1,r);
                c.insert(k);
                write(c.getmax(v));
                out[len++]='\n';
            }
        }
    }
    fwrite(out,1,len,stdout);
    return 0;
}
  /*
  Time:7.25s
  Memory:31.10MB
  AC
  100pts
  */

这是我做的第四道 Ynoi,写的第一篇 Ynoi 题解,希望大家支持,谢谢。

posted @   ffffyc  阅读(16)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示