zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
    卷也卷不过,躺又躺不平
  • 相关阅读:
    Anagram
    HDU 1205 吃糖果(鸽巢原理)
    Codeforces 1243D 0-1 MST(补图的连通图数量)
    Codeforces 1243C Tile Painting(素数)
    Codeforces 1243B2 Character Swap (Hard Version)
    Codeforces 1243B1 Character Swap (Easy Version)
    Codeforces 1243A Maximum Square
    Codeforces 1272E Nearest Opposite Parity(BFS)
    Codeforces 1272D Remove One Element
    Codeforces 1272C Yet Another Broken Keyboard
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/14547433.html
Copyright © 2011-2022 走看看