首页 > 其他分享 >[ [Ynoi2013] 无力回天 NOI2017 ] 解题报告

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

时间:2023-03-25 09:01:20浏览次数:45  
标签:无力回天 return int void Ynoi2013 异或 NOI2017 线性 define

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

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

可以发现虽然不允许区间修改,但允许单点修改。区间转单点,想到了什么?差分!考虑令 \(b\) 表示原数组的异或差分数组,即 \(b_i=\begin{cases}a_i&\text{若}\ i=1\\a_{i-1}\oplus a_i&\text{若}\ i\not=1\end{cases}\)。反过来,\(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;
}

标签:无力回天,return,int,void,Ynoi2013,异或,NOI2017,线性,define
From: https://www.cnblogs.com/luoshen0/p/17253511.html

相关文章

  • 【题解】[Ynoi2013] 大学
    题目分析:考虑对于一次修改至少会让\(x\)变成\(\frac{x}{2}\)所以对于每一个数最多被操作\(\log{n}\)次,那么直接暴力操作就好了。所以其实关键问题是每次怎么找到哪......
  • LuoguP5354 [Ynoi2017]由乃的OJ题解
    P5354[Ynoi2017]由乃的OJPreface自己的由乃题一血,写篇题解纪念一下。Description给定一颗\(n\)个结点的树,每个结点都有一个权值\(a_i\)和一个位运算符\(\mathrm{......
  • 【题解】[Ynoi2013] 文化课
    题目分析:这个权值一看就可以使用线段树维护啊,因为很明显可以进行高效合并。对于区间合并其实就只是需要判断一下两个区间中间如果是乘号,那么造成的贡献要变成区间两边乘......
  • P5366 [SNOI2017]遗失的答案
    链接:https://www.luogu.com.cn/problem/P5366题目描述:有\(n\)个数\(1\)到\(n\),给定\(q\)组询问,每组询问形如求选择一些数且必须选\(x\)且最大公约数为\(G\),最小公倍数为......
  • [Ynoi2013]大学
    链接:https://www.luogu.com.cn/problem/P5610题目描述:给定一个长为\(n\)的序列\(a\),支持区间为\(d\)倍数的除以\(d\)的操作,以及区间查询和的操作,强制在线。题解:可以发现......
  • [AHOI2017/HNOI2017]礼物
    链接:https://www.luogu.com.cn/problem/P3723题目描述:给定两个序列,每次可以旋转其中的一个或给其中一个加上一个数\(c\),求两个序列对应位置的差的平方和所能达到的最小值......
  • [AHOI2017/HNOI2017]礼物
    链接:https://www.luogu.com.cn/problem/P3723题目描述:给定两个序列,每次可以旋转其中的一个或给其中一个加上一个数$c$,求两个序列对应位置的差的平方和所能达到的最小值。......
  • 【HNOI2017】礼物(FFT)
    显然,\(y_i\)加上\(c\)可以看成是\(x_i\)减去\(c\)。所以就变成了\(x_i\)加上一个整数(可正可负)。现将\(x\)环拆成一个长度为\(2n\)的序列\(a\)(复制一遍),把\(......
  • BZOJ 4810([Ynoi2017]由乃的玉米田-莫队)
    Description由乃在自己的农田边散步,她突然发现田里的一排玉米非常的不美。这排玉米一共有N株,它们的高度参差不齐。由乃认为玉米田不美,所以她决定出个数据结构题这个题是这......
  • 线段树优化建图 (CF786B、SNOI2017炸弹)
    先来看板子题:CF786B可以发现,如果对着区间内的每一个点都建一条边,然后跑最短路,我们无论是在空间还是时间复杂度上都是过不去的。因此,我们请出老朋友线段树。参考上图。......