• P4839 P哥的桶 题解(线段树维护线性基)


    题目链接

    题目大意

    (n)个桶,(m)次操作

    操作分为两种

    • (pos)桶中加入一个(val)

    • ([l,r])中选任意个桶使得异或和最大,求最大的异或和

    注意每个节点是一个桶可以放多个值

    (n,mleq 5 imes 10^4)

    题目思路

    单点修改,区间查询,异或最大值

    很显然是线段树维护线性基

    然后这样的复杂度是(O(n imes log^3))

    然而会(TLE)

    看了一下大佬的题解,更新的时候没有必要维护两个子节点的并集

    只需要从上往下更新,每到一个节点就更新其线性基维护的值就好了。

    查询的时候每次都将不同区间所维护的线性基合并到答案即可

    插入复杂度(O(n imes log^2))

    查询复杂度(O(n imes log^3))

    但是这个查询的常数还是大大优化了

    TLE代码

    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    typedef long long ll;
    typedef pair<double,int> pdi;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    const int maxn=5e4+5,mod=1e7;
    int n,m;
    int a[maxn];
    int p[40];
    vector<int> tree[maxn<<2];
    void ins(int x) {
        for(int i = 30;i>=0; i--) {
            if (!(x &(1<<i)))  continue;
            // x的第i位是0
            if(!p[i]){
                p[i] = x;
                break;
            }
            x^= p[i];
        }
    }
    vector<int> mer(vector<int> a,vector<int> b){
        vector<int> ans;
        memset(p,0,sizeof(p));
        for(int i=0;i<a.size();i++) ins(a[i]);
        for(int i=0;i<b.size();i++) ins(b[i]);
        for(int i=0;i<=30;i++){
            if(p[i]!=0){
                ans.push_back(p[i]);
            }
        }
        return ans;
    }
    void update(int node,int pos,int l,int r,int val){
        if(l==r){
            vector<int> temp;
            temp.push_back(val);
            tree[node]=mer(tree[node],temp);
            return ;
        }
        int mid=(l+r)/2;
        if(mid>=pos) update(node<<1,pos,l,mid,val);
        else  update(node<<1|1,pos,mid+1,r,val);
        tree[node]=mer(tree[node<<1],tree[node<<1|1]);
    }
    vector<int> query(int node,int L,int R,int l,int r){
        if(L<=l&&r<=R){
            return tree[node];
        }
        vector<int> ans;
        int mid=(l+r)/2;
        if(mid>=L) ans=mer(ans,query(node<<1,L,R,l,mid));
        if(mid<R)  ans=mer(ans,query(node<<1|1,L,R,mid+1,r));
        return ans;
    }
    signed main(){
        scanf("%d%d",&m,&n);
        for(int i=1,opt,pos,val,l,r;i<=m;i++){
            scanf("%d",&opt);
            if(opt==1){
                scanf("%d%d",&pos,&val);
                update(1,pos,1,n,val);
            }else{
                scanf("%d%d",&l,&r);
                vector<int> ans=query(1,l,r,1,n);
                int pr=0;
                for(int j=(int)ans.size()-1;j>=0;j--){
                    pr=max(pr,pr^ans[j]);
                }
                printf("%d
    ",pr);
            }
        }
        return 0;
    }
    

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    typedef long long ll;
    typedef pair<double,int> pdi;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    const int maxn=5e4+5,mod=1e7;
    int n,m;
    int a[maxn];
    int tree[maxn<<2][40];
    void ins(int pos,int x) {
        for(int i = 30;i>=0; i--) {
            if (!(x &(1<<i)))  continue;
            // x的第i位是0
            if(!tree[pos][i]){
                tree[pos][i] = x;
                break;
            }
            x^= tree[pos][i];
        }
    }
    void update(int node,int pos,int l,int r,int val){
        ins(node,val);
        if(l==r){
            return ;
        }
        int mid=(l+r)/2;
        if(mid>=pos) update(node<<1,pos,l,mid,val);
        else  update(node<<1|1,pos,mid+1,r,val);
    }
    void query(int node,int L,int R,int l,int r){
        if(L<=l&&r<=R){
            for(int i=0;i<=30;i++){
                if(!tree[node][i]) continue;
                ins(0,tree[node][i]);
            }
            return ;
        }
        int mid=(l+r)/2;
        if(mid>=L) query(node<<1,L,R,l,mid);
        if(mid<R)  query(node<<1|1,L,R,mid+1,r);
    }
    
    signed main(){
        scanf("%d%d",&m,&n);
        for(int i=1,opt,pos,val,l,r;i<=m;i++){
            scanf("%d",&opt);
            if(opt==1){
                scanf("%d%d",&pos,&val);
                update(1,pos,1,n,val);
            }else{
                scanf("%d%d",&l,&r);
                memset(tree[0],0,sizeof(tree[0]));
                query(1,l,r,1,n);
                int pr=0;
                for(int i=30;i>=0;i--){ // tree[0]为答案
                    pr=max(pr,pr^tree[0][i]);
                }
                printf("%d
    ",pr);
            }
        }
        return 0;
    }
    
    
    卷也卷不过,躺又躺不平
  • 相关阅读:
    20165339 预备作业3 Linux安装及学习
    20165339 学习基础和c语言基础调查
    20165339 我期望的师生关系
    2018-2019-1 20165332 《信息安全系统设计基础》第3周学习总结
    2018-2019-1 20165332 《信息安全系统设计基础》第2周学习总结
    2018-2019-1 20165332 《信息安全系统设计基础》第1周学习总结
    20165332 2017-2018-2《Java程序设计》课程总结
    20165332实验五 网络编程与安全
    20165332实验四 Android开发基础
    20165332第十周课下作业
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/14547433.html
Copyright © 2020-2023  润新知