[ [Ynoi2013] 无力回天 NOI2017 ] 解题报告

Posted 无心随笔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ [Ynoi2013] 无力回天 NOI2017 ] 解题报告相关的知识,希望对你有一定的参考价值。

[Ynoi2013] 无力回天 NOI2017
首先看到异或,想到能维护异或的东西就那几样(线性基/01trie/数位 dp/FWT),再看到求选任意个数后的异或最大值,线性基无疑了。

这时再看还要维护什么其它信息,区间异或,区间查询,一副线段树维护线性基的样子。但我们知道线性基中的值一旦修改就必须重构,区间修改的时间复杂度不允许,尝试优化这个做法。

可以发现虽然不允许区间修改,但允许单点修改。区间转单点,想到了什么?差分!考虑令 \\(b\\) 表示原数组的异或差分数组,即 \\(b_i=\\begincasesa_i&\\text若\\ i=1\\\\a_i-1\\oplus a_i&\\text若\\ i\\not=1\\endcases\\)。反过来,\\(a_i\\)\\(b\\) 的异或前缀和。可以发现每次区间异或操作相当于修改 \\(b_l\\)\\(b_r+1\\) 两个值。

又因为若线性基中的数能表示 \\(a_i-1\\),那么再插入一个 \\(b_i\\) 一定能够表示 \\(a_i\\)。所以 \\(\\a_l,a_l+1,a_l+2,\\dots,a_r\\\\) 的线性基等价于在 \\(\\b_l+1,b_l+2,\\dots,b_r\\\\) 的线性基中插入 \\(a_l\\) 后的线性基。因此用线段树维护 \\(b_l,b_l+1,b_l+2,\\dots,b_r\\) 的线性基,每次修改操作重构 \\(l\\)\\(r+1\\) 处的线性基即可。复杂度 \\(O(n\\log^3n)\\)

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pdi pair<double,int>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define eps 1e-9
using namespace std;
namespace IO
    template<typename T>
    inline void read(T &x)
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>\'9\'||ch<\'0\')
            if(ch==\'-\')
                f=-1;
    
            ch=getchar();
        
        while(ch>=\'0\'&&ch<=\'9\')
            x=x*10+(ch-\'0\');
            ch=getchar();
        
        x=(f==1?x:-x);
    
    template<typename T>
    inline void write(T x)
        if(x<0)
            putchar(\'-\');
            x=-x;
        
        if(x>=10)
            write(x/10);
        
        putchar(x%10+\'0\');
    
    template<typename T>
    inline void write_endl(T x)
        write(x);
        putchar(\'\\n\');
    
    template<typename T>
    inline void write_space(T x)
        write(x);
        putchar(\' \');
    

using namespace IO;
const int N=5e4+10,Lg=30;
int a[N],b[N],n,q;
struct base
    int p[35];
    void ins(int &x)
        for(int i=Lg;i>=0;i--)
            if(x>>i&1)
                if(!p[i])
                    p[i]=x;
                    break;
                
                else
                    x^=p[i];
                
            
        
    
    void clear()
        for(int i=Lg;i>=0;i--)
            p[i]=0;
        
    
    int query(int mx)
        for(int i=Lg;i>=0;i--)
            if((mx^p[i])>=mx)
                mx^=p[i];
            
        
        return mx;
    
;
base merge(base x,base y)
    for(int i=Lg;i>=0;i--)
        x.ins(y.p[i]);
    
    return x;

namespace Seg_Tree
    base ans[N<<2];
    #define ls(p) p<<1
    #define rs(p) p<<1|1
    void push_up(int p)
        ans[p]=merge(ans[ls(p)],ans[rs(p)]);
    
    void build(int p,int l,int r)
        if(l==r)
            ans[p].ins(b[l]);
            return;
        
        int mid=(l+r)>>1;
        build(ls(p),l,mid);
        build(rs(p),mid+1,r);
        push_up(p);
    
    void update(int p,int l,int r,int pos,int val)
        if(l==r)
            ans[p].clear();
            b[l]^=val;
            ans[p].ins(b[l]);
            return;
        
        int mid=(l+r)>>1;
        if(pos<=mid)
            update(ls(p),l,mid,pos,val);
        
        else
            update(rs(p),mid+1,r,pos,val);
        
        push_up(p);
    
    base query(int p,int l,int r,int q_l,int q_r)
        if(q_l<=l&&r<=q_r)
            return ans[p];
        
        int mid=(l+r)>>1;
        if(q_r<=mid)
            return query(ls(p),l,mid,q_l,q_r);
        
        if(q_l>mid)
            return query(rs(p),mid+1,r,q_l,q_r);
        
        return merge(query(ls(p),l,mid,q_l,q_r),query(rs(p),mid+1,r,q_l,q_r));
    

namespace Fenwick_Tree
    int ans[N];
    int lowbit(int x)
        return x&(-x);
    
    void update(int pos,int val)
        while(pos<=n)
            ans[pos]^=val;
            pos+=lowbit(pos);
        
    
    int query(int pos)
        int res=0;
        while(pos)
            res^=ans[pos];
            pos-=lowbit(pos);
        
        return res;
    

signed main()
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    read(n),read(q);
    for(int i=1;i<=n;i++)
        read(a[i]);
        b[i]=a[i]^a[i-1];
    
    Seg_Tree::build(1,1,n);
    for(int i=1;i<=n;i++)
        Fenwick_Tree::update(i,b[i]);
    
    while(q--)
        int opt,l,r,val;
        read(opt),read(l),read(r),read(val);
        if(opt==1)
            Seg_Tree::update(1,1,n,l,val);
            Fenwick_Tree::update(l,val);
            if(r<n)
                Seg_Tree::update(1,1,n,r+1,val);
                Fenwick_Tree::update(r+1,val);
            
        
        else
            int x=Fenwick_Tree::query(l);
            base y;
            y.clear();
            if(l!=r)
                y=Seg_Tree::query(1,1,n,l+1,r);
            
            y.ins(x);
            write_endl(y.query(val));
        
    
    return 0;

以上是关于[ [Ynoi2013] 无力回天 NOI2017 ] 解题报告的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4811[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并

BZOJ4810: [Ynoi2017]由乃的玉米田

bzoj 4811: [Ynoi2017]由乃的OJ

BZOJ4811[Ynoi2017]由乃的OJ 树链剖分+线段树

BZOJ4811 [Ynoi2017]由乃的OJ

BZOJ4810 [Ynoi2017]由乃的玉米田